loading
Generated 2025-01-14T14:13:50-05:00

All Files ( 0.68% covered at 0.01 hits/line )

140 files in total.
6481 relevant lines, 44 lines covered and 6437 lines missed. ( 0.68% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/controllers/admin/assets_controller.rb 0.00 % 95 84 0 84 0.00
app/controllers/admin/configuration_controller.rb 0.00 % 48 38 0 38 0.00
app/controllers/admin/extensions_controller.rb 0.00 % 12 11 0 11 0.00
app/controllers/admin/layouts_controller.rb 0.00 % 8 8 0 8 0.00
app/controllers/admin/page_attachments_controller.rb 0.00 % 23 19 0 19 0.00
app/controllers/admin/page_fields_controller.rb 0.00 % 15 13 0 13 0.00
app/controllers/admin/page_parts_controller.rb 0.00 % 15 13 0 13 0.00
app/controllers/admin/pages_controller.rb 0.00 % 176 152 0 152 0.00
app/controllers/admin/preferences_controller.rb 0.00 % 33 27 0 27 0.00
app/controllers/admin/references_controller.rb 0.00 % 14 12 0 12 0.00
app/controllers/admin/resource_controller.rb 0.00 % 267 187 0 187 0.00
app/controllers/admin/sites_controller.rb 0.00 % 15 14 0 14 0.00
app/controllers/admin/snippets_controller.rb 0.00 % 8 8 0 8 0.00
app/controllers/admin/users_controller.rb 37.14 % 62 35 13 22 0.37
app/controllers/application_controller.rb 0.00 % 96 75 0 75 0.00
app/controllers/page_status_controller.rb 0.00 % 61 50 0 50 0.00
app/controllers/site_controller.rb 0.00 % 97 67 0 67 0.00
app/controllers/social_mailer_controller.rb 0.00 % 26 23 0 23 0.00
app/helpers/admin/configuration_helper.rb 0.00 % 80 54 0 54 0.00
app/helpers/admin/export_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/extensions_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/layouts_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/node_helper.rb 0.00 % 109 94 0 94 0.00
app/helpers/admin/page_attachments_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/pages_helper.rb 0.00 % 20 16 0 16 0.00
app/helpers/admin/preferences_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/references_helper.rb 0.00 % 45 40 0 40 0.00
app/helpers/admin/regions_helper.rb 0.00 % 30 27 0 27 0.00
app/helpers/admin/resource_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/users_helper.rb 28.57 % 9 7 2 5 0.29
app/helpers/admin/welcome_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/application_helper.rb 0.00 % 179 145 0 145 0.00
app/helpers/rad_social_helper.rb 0.00 % 20 18 0 18 0.00
app/helpers/scoped_helper.rb 0.00 % 17 16 0 16 0.00
app/helpers/site_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/sites_helper.rb 0.00 % 10 10 0 10 0.00
app/mailers/application_mailer.rb 0.00 % 2 2 0 2 0.00
app/mailers/devise_mailer.rb 0.00 % 7 7 0 7 0.00
app/mailers/rad_social_mailer.rb 0.00 % 25 21 0 21 0.00
app/models/admins_site.rb 0.00 % 6 5 0 5 0.00
app/models/asset.rb 0.00 % 249 195 0 195 0.00
app/models/asset_type.rb 0.00 % 235 172 0 172 0.00
app/models/file_not_found_page.rb 0.00 % 30 24 0 24 0.00
app/models/haml_filter.rb 0.00 % 5 5 0 5 0.00
app/models/layout.rb 100.00 % 14 8 8 0 1.63
app/models/menu_renderer.rb 0.00 % 138 111 0 111 0.00
app/models/page.rb 0.00 % 398 319 0 319 0.00
app/models/page_attachment.rb 0.00 % 19 13 0 13 0.00
app/models/page_context.rb 0.00 % 46 38 0 38 0.00
app/models/page_field.rb 0.00 % 4 4 0 4 0.00
app/models/page_part.rb 0.00 % 20 12 0 12 0.00
app/models/rails_page.rb 0.00 % 28 24 0 24 0.00
app/models/site.rb 0.00 % 90 62 0 62 0.00
app/models/snippet.rb 91.67 % 21 12 11 1 1.33
app/models/snippet_finder.rb 0.00 % 24 20 0 20 0.00
app/models/snippet_tags.rb 0.00 % 80 61 0 61 0.00
app/models/standard_tags.rb 0.00 % 1121 936 0 936 0.00
app/models/status.rb 0.00 % 37 30 0 30 0.00
app/models/text_filter.rb 62.50 % 31 16 10 6 0.63
app/models/trusty_cms/config.rb 0.00 % 313 152 0 152 0.00
app/models/trusty_cms/page_response_cache_director.rb 0.00 % 42 34 0 34 0.00
app/models/user.rb 0.00 % 81 55 0 55 0.00
app/models/user_action_observer.rb 0.00 % 27 19 0 19 0.00
lib/active_record_extensions/active_record_extensions.rb 0.00 % 24 23 0 23 0.00
lib/annotatable.rb 0.00 % 66 57 0 57 0.00
lib/configuration_extensions/configuration_extensions.rb 0.00 % 321 177 0 177 0.00
lib/generators/extension/extension_generator.rb 0.00 % 97 82 0 82 0.00
lib/generators/extension/templates/cucumber_env.rb 0.00 % 11 7 0 7 0.00
lib/generators/extension/templates/cucumber_paths.rb 0.00 % 20 6 0 6 0.00
lib/generators/extension/templates/extension.rb 0.00 % 20 10 0 10 0.00
lib/generators/extension/templates/functional_test.rb 0.00 % 15 10 0 10 0.00
lib/generators/extension/templates/gemspec.rb 0.00 % 29 20 0 20 0.00
lib/generators/extension/templates/lib.rb 0.00 % 8 8 0 8 0.00
lib/generators/extension/templates/migration.rb 0.00 % 9 6 0 6 0.00
lib/generators/extension/templates/radiant_config.rb 0.00 % 3 2 0 2 0.00
lib/generators/extension/templates/routes.rb 0.00 % 5 2 0 2 0.00
lib/generators/extension/templates/spec_helper.rb 0.00 % 42 23 0 23 0.00
lib/generators/extension/templates/test_helper.rb 0.00 % 24 17 0 17 0.00
lib/generators/extension_controller/extension_controller_generator.rb 0.00 % 83 64 0 64 0.00
lib/generators/extension_controller/templates/controller.rb 0.00 % 10 6 0 6 0.00
lib/generators/extension_controller/templates/controller_spec.rb 0.00 % 23 17 0 17 0.00
lib/generators/extension_controller/templates/functional_test.rb 0.00 % 11 7 0 7 0.00
lib/generators/extension_controller/templates/helper.rb 0.00 % 2 2 0 2 0.00
lib/generators/extension_controller/templates/helper_spec.rb 0.00 % 11 7 0 7 0.00
lib/generators/extension_controller/templates/helper_test.rb 0.00 % 4 3 0 3 0.00
lib/generators/extension_controller/templates/view_spec.rb 0.00 % 12 9 0 9 0.00
lib/generators/extension_mailer/extension_mailer_generator.rb 0.00 % 67 50 0 50 0.00
lib/generators/extension_mailer/templates/mailer.rb 0.00 % 15 11 0 11 0.00
lib/generators/extension_mailer/templates/unit_test.rb 0.00 % 21 17 0 17 0.00
lib/generators/extension_migration/extension_migration_generator.rb 0.00 % 24 19 0 19 0.00
lib/generators/extension_migration/templates/migration.rb 0.00 % 11 10 0 10 0.00
lib/generators/extension_model/extension_model_generator.rb 0.00 % 67 50 0 50 0.00
lib/generators/extension_model/templates/migration.rb 0.00 % 16 15 0 15 0.00
lib/generators/extension_model/templates/model.rb 0.00 % 2 2 0 2 0.00
lib/generators/extension_model/templates/model_spec.rb 0.00 % 11 9 0 9 0.00
lib/generators/extension_model/templates/unit_test.rb 0.00 % 8 6 0 6 0.00
lib/generators/generator_base_extension.rb 0.00 % 17 15 0 15 0.00
lib/generators/instance/instance_generator.rb 0.00 % 151 112 0 112 0.00
lib/generators/instance/templates/instance_boot.rb 0.00 % 122 97 0 97 0.00
lib/generators/instance/templates/instance_environment.rb 0.00 % 92 33 0 33 0.00
lib/generators/instance/templates/instance_radiant_config.rb 0.00 % 16 2 0 2 0.00
lib/generators/instance/templates/instance_routes.rb 0.00 % 1 1 0 1 0.00
lib/generators/language_extension/language_extension_generator.rb 0.00 % 70 52 0 52 0.00
lib/generators/language_extension/templates/cucumber_env.rb 0.00 % 16 10 0 10 0.00
lib/generators/language_extension/templates/cucumber_paths.rb 0.00 % 14 10 0 10 0.00
lib/generators/language_extension/templates/extension.rb 0.00 % 11 8 0 8 0.00
lib/generators/language_extension/templates/functional_test.rb 0.00 % 15 10 0 10 0.00
lib/generators/language_extension/templates/gemspec.rb 0.00 % 24 20 0 20 0.00
lib/generators/language_extension/templates/lib.rb 0.00 % 8 8 0 8 0.00
lib/generators/language_extension/templates/spec_helper.rb 0.00 % 36 18 0 18 0.00
lib/generators/language_extension/templates/test_helper.rb 0.00 % 24 17 0 17 0.00
lib/generators/trusty_cms/trusty_cms_generator.rb 0.00 % 29 24 0 24 0.00
lib/inheritable_class_attributes.rb 0.00 % 69 61 0 61 0.00
lib/login_system.rb 0.00 % 127 83 0 83 0.00
lib/method_observer.rb 0.00 % 51 42 0 42 0.00
lib/ostruct.rb 0.00 % 51 44 0 44 0.00
lib/simpleton.rb 0.00 % 17 15 0 15 0.00
lib/string_extensions/string_extensions.rb 0.00 % 25 20 0 20 0.00
lib/symbol_extensions/symbol_extensions.rb 0.00 % 5 5 0 5 0.00
lib/translation_support.rb 0.00 % 54 44 0 44 0.00
lib/trusty_cms.rb 0.00 % 8 5 0 5 0.00
lib/trusty_cms/admin_ui.rb 0.00 % 253 213 0 213 0.00
lib/trusty_cms/admin_ui/region_partials.rb 0.00 % 24 19 0 19 0.00
lib/trusty_cms/admin_ui/region_set.rb 0.00 % 34 30 0 30 0.00
lib/trusty_cms/available_locales.rb 0.00 % 17 15 0 15 0.00
lib/trusty_cms/config/definition.rb 0.00 % 145 78 0 78 0.00
lib/trusty_cms/deprecation.rb 0.00 % 13 10 0 10 0.00
lib/trusty_cms/engine.rb 0.00 % 27 26 0 26 0.00
lib/trusty_cms/extension.rb 0.00 % 135 105 0 105 0.00
lib/trusty_cms/extension_loader.rb 0.00 % 149 87 0 87 0.00
lib/trusty_cms/extension_migrator.rb 0.00 % 83 69 0 69 0.00
lib/trusty_cms/extension_path.rb 0.00 % 201 90 0 90 0.00
lib/trusty_cms/initializer.rb 0.00 % 153 76 0 76 0.00
lib/trusty_cms/pagination/controller.rb 0.00 % 38 25 0 25 0.00
lib/trusty_cms/pagination/link_renderer.rb 0.00 % 34 25 0 25 0.00
lib/trusty_cms/resource_responses.rb 0.00 % 122 105 0 105 0.00
lib/trusty_cms/setup.rb 0.00 % 226 200 0 200 0.00
lib/trusty_cms/taggable.rb 0.00 % 135 100 0 100 0.00
lib/trusty_cms/task_support.rb 0.00 % 69 59 0 59 0.00
lib/trusty_cms/version.rb 0.00 % 4 3 0 3 0.00

Controllers ( 1.56% covered at 0.02 hits/line )

18 files in total.
836 relevant lines, 13 lines covered and 823 lines missed. ( 1.56% )

Channels ( 100.0% covered at 0.0 hits/line )

0 files in total.
0 relevant lines, 0 lines covered and 0 lines missed. ( 100.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line

Models ( 1.25% covered at 0.02 hits/line )

24 files in total.
2327 relevant lines, 29 lines covered and 2298 lines missed. ( 1.25% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/models/admins_site.rb 0.00 % 6 5 0 5 0.00
app/models/asset.rb 0.00 % 249 195 0 195 0.00
app/models/asset_type.rb 0.00 % 235 172 0 172 0.00
app/models/file_not_found_page.rb 0.00 % 30 24 0 24 0.00
app/models/haml_filter.rb 0.00 % 5 5 0 5 0.00
app/models/layout.rb 100.00 % 14 8 8 0 1.63
app/models/menu_renderer.rb 0.00 % 138 111 0 111 0.00
app/models/page.rb 0.00 % 398 319 0 319 0.00
app/models/page_attachment.rb 0.00 % 19 13 0 13 0.00
app/models/page_context.rb 0.00 % 46 38 0 38 0.00
app/models/page_field.rb 0.00 % 4 4 0 4 0.00
app/models/page_part.rb 0.00 % 20 12 0 12 0.00
app/models/rails_page.rb 0.00 % 28 24 0 24 0.00
app/models/site.rb 0.00 % 90 62 0 62 0.00
app/models/snippet.rb 91.67 % 21 12 11 1 1.33
app/models/snippet_finder.rb 0.00 % 24 20 0 20 0.00
app/models/snippet_tags.rb 0.00 % 80 61 0 61 0.00
app/models/standard_tags.rb 0.00 % 1121 936 0 936 0.00
app/models/status.rb 0.00 % 37 30 0 30 0.00
app/models/text_filter.rb 62.50 % 31 16 10 6 0.63
app/models/trusty_cms/config.rb 0.00 % 313 152 0 152 0.00
app/models/trusty_cms/page_response_cache_director.rb 0.00 % 42 34 0 34 0.00
app/models/user.rb 0.00 % 81 55 0 55 0.00
app/models/user_action_observer.rb 0.00 % 27 19 0 19 0.00

Mailers ( 0.0% covered at 0.0 hits/line )

3 files in total.
30 relevant lines, 0 lines covered and 30 lines missed. ( 0.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/mailers/application_mailer.rb 0.00 % 2 2 0 2 0.00
app/mailers/devise_mailer.rb 0.00 % 7 7 0 7 0.00
app/mailers/rad_social_mailer.rb 0.00 % 25 21 0 21 0.00

Helpers ( 0.45% covered at 0.0 hits/line )

18 files in total.
443 relevant lines, 2 lines covered and 441 lines missed. ( 0.45% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
app/helpers/admin/configuration_helper.rb 0.00 % 80 54 0 54 0.00
app/helpers/admin/export_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/extensions_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/layouts_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/node_helper.rb 0.00 % 109 94 0 94 0.00
app/helpers/admin/page_attachments_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/pages_helper.rb 0.00 % 20 16 0 16 0.00
app/helpers/admin/preferences_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/references_helper.rb 0.00 % 45 40 0 40 0.00
app/helpers/admin/regions_helper.rb 0.00 % 30 27 0 27 0.00
app/helpers/admin/resource_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/admin/users_helper.rb 28.57 % 9 7 2 5 0.29
app/helpers/admin/welcome_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/application_helper.rb 0.00 % 179 145 0 145 0.00
app/helpers/rad_social_helper.rb 0.00 % 20 18 0 18 0.00
app/helpers/scoped_helper.rb 0.00 % 17 16 0 16 0.00
app/helpers/site_helper.rb 0.00 % 2 2 0 2 0.00
app/helpers/sites_helper.rb 0.00 % 10 10 0 10 0.00

Jobs ( 100.0% covered at 0.0 hits/line )

0 files in total.
0 relevant lines, 0 lines covered and 0 lines missed. ( 100.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line

Libraries ( 0.0% covered at 0.0 hits/line )

77 files in total.
2845 relevant lines, 0 lines covered and 2845 lines missed. ( 0.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
lib/active_record_extensions/active_record_extensions.rb 0.00 % 24 23 0 23 0.00
lib/annotatable.rb 0.00 % 66 57 0 57 0.00
lib/configuration_extensions/configuration_extensions.rb 0.00 % 321 177 0 177 0.00
lib/generators/extension/extension_generator.rb 0.00 % 97 82 0 82 0.00
lib/generators/extension/templates/cucumber_env.rb 0.00 % 11 7 0 7 0.00
lib/generators/extension/templates/cucumber_paths.rb 0.00 % 20 6 0 6 0.00
lib/generators/extension/templates/extension.rb 0.00 % 20 10 0 10 0.00
lib/generators/extension/templates/functional_test.rb 0.00 % 15 10 0 10 0.00
lib/generators/extension/templates/gemspec.rb 0.00 % 29 20 0 20 0.00
lib/generators/extension/templates/lib.rb 0.00 % 8 8 0 8 0.00
lib/generators/extension/templates/migration.rb 0.00 % 9 6 0 6 0.00
lib/generators/extension/templates/radiant_config.rb 0.00 % 3 2 0 2 0.00
lib/generators/extension/templates/routes.rb 0.00 % 5 2 0 2 0.00
lib/generators/extension/templates/spec_helper.rb 0.00 % 42 23 0 23 0.00
lib/generators/extension/templates/test_helper.rb 0.00 % 24 17 0 17 0.00
lib/generators/extension_controller/extension_controller_generator.rb 0.00 % 83 64 0 64 0.00
lib/generators/extension_controller/templates/controller.rb 0.00 % 10 6 0 6 0.00
lib/generators/extension_controller/templates/controller_spec.rb 0.00 % 23 17 0 17 0.00
lib/generators/extension_controller/templates/functional_test.rb 0.00 % 11 7 0 7 0.00
lib/generators/extension_controller/templates/helper.rb 0.00 % 2 2 0 2 0.00
lib/generators/extension_controller/templates/helper_spec.rb 0.00 % 11 7 0 7 0.00
lib/generators/extension_controller/templates/helper_test.rb 0.00 % 4 3 0 3 0.00
lib/generators/extension_controller/templates/view_spec.rb 0.00 % 12 9 0 9 0.00
lib/generators/extension_mailer/extension_mailer_generator.rb 0.00 % 67 50 0 50 0.00
lib/generators/extension_mailer/templates/mailer.rb 0.00 % 15 11 0 11 0.00
lib/generators/extension_mailer/templates/unit_test.rb 0.00 % 21 17 0 17 0.00
lib/generators/extension_migration/extension_migration_generator.rb 0.00 % 24 19 0 19 0.00
lib/generators/extension_migration/templates/migration.rb 0.00 % 11 10 0 10 0.00
lib/generators/extension_model/extension_model_generator.rb 0.00 % 67 50 0 50 0.00
lib/generators/extension_model/templates/migration.rb 0.00 % 16 15 0 15 0.00
lib/generators/extension_model/templates/model.rb 0.00 % 2 2 0 2 0.00
lib/generators/extension_model/templates/model_spec.rb 0.00 % 11 9 0 9 0.00
lib/generators/extension_model/templates/unit_test.rb 0.00 % 8 6 0 6 0.00
lib/generators/generator_base_extension.rb 0.00 % 17 15 0 15 0.00
lib/generators/instance/instance_generator.rb 0.00 % 151 112 0 112 0.00
lib/generators/instance/templates/instance_boot.rb 0.00 % 122 97 0 97 0.00
lib/generators/instance/templates/instance_environment.rb 0.00 % 92 33 0 33 0.00
lib/generators/instance/templates/instance_radiant_config.rb 0.00 % 16 2 0 2 0.00
lib/generators/instance/templates/instance_routes.rb 0.00 % 1 1 0 1 0.00
lib/generators/language_extension/language_extension_generator.rb 0.00 % 70 52 0 52 0.00
lib/generators/language_extension/templates/cucumber_env.rb 0.00 % 16 10 0 10 0.00
lib/generators/language_extension/templates/cucumber_paths.rb 0.00 % 14 10 0 10 0.00
lib/generators/language_extension/templates/extension.rb 0.00 % 11 8 0 8 0.00
lib/generators/language_extension/templates/functional_test.rb 0.00 % 15 10 0 10 0.00
lib/generators/language_extension/templates/gemspec.rb 0.00 % 24 20 0 20 0.00
lib/generators/language_extension/templates/lib.rb 0.00 % 8 8 0 8 0.00
lib/generators/language_extension/templates/spec_helper.rb 0.00 % 36 18 0 18 0.00
lib/generators/language_extension/templates/test_helper.rb 0.00 % 24 17 0 17 0.00
lib/generators/trusty_cms/trusty_cms_generator.rb 0.00 % 29 24 0 24 0.00
lib/inheritable_class_attributes.rb 0.00 % 69 61 0 61 0.00
lib/login_system.rb 0.00 % 127 83 0 83 0.00
lib/method_observer.rb 0.00 % 51 42 0 42 0.00
lib/ostruct.rb 0.00 % 51 44 0 44 0.00
lib/simpleton.rb 0.00 % 17 15 0 15 0.00
lib/string_extensions/string_extensions.rb 0.00 % 25 20 0 20 0.00
lib/symbol_extensions/symbol_extensions.rb 0.00 % 5 5 0 5 0.00
lib/translation_support.rb 0.00 % 54 44 0 44 0.00
lib/trusty_cms.rb 0.00 % 8 5 0 5 0.00
lib/trusty_cms/admin_ui.rb 0.00 % 253 213 0 213 0.00
lib/trusty_cms/admin_ui/region_partials.rb 0.00 % 24 19 0 19 0.00
lib/trusty_cms/admin_ui/region_set.rb 0.00 % 34 30 0 30 0.00
lib/trusty_cms/available_locales.rb 0.00 % 17 15 0 15 0.00
lib/trusty_cms/config/definition.rb 0.00 % 145 78 0 78 0.00
lib/trusty_cms/deprecation.rb 0.00 % 13 10 0 10 0.00
lib/trusty_cms/engine.rb 0.00 % 27 26 0 26 0.00
lib/trusty_cms/extension.rb 0.00 % 135 105 0 105 0.00
lib/trusty_cms/extension_loader.rb 0.00 % 149 87 0 87 0.00
lib/trusty_cms/extension_migrator.rb 0.00 % 83 69 0 69 0.00
lib/trusty_cms/extension_path.rb 0.00 % 201 90 0 90 0.00
lib/trusty_cms/initializer.rb 0.00 % 153 76 0 76 0.00
lib/trusty_cms/pagination/controller.rb 0.00 % 38 25 0 25 0.00
lib/trusty_cms/pagination/link_renderer.rb 0.00 % 34 25 0 25 0.00
lib/trusty_cms/resource_responses.rb 0.00 % 122 105 0 105 0.00
lib/trusty_cms/setup.rb 0.00 % 226 200 0 200 0.00
lib/trusty_cms/taggable.rb 0.00 % 135 100 0 100 0.00
lib/trusty_cms/task_support.rb 0.00 % 69 59 0 59 0.00
lib/trusty_cms/version.rb 0.00 % 4 3 0 3 0.00

app/controllers/admin/assets_controller.rb

0.0% lines covered

84 relevant lines. 0 lines covered and 84 lines missed.
    
  1. class Admin::AssetsController < Admin::ResourceController
  2. paginate_models(per_page: 50)
  3. COMPRESS_FILE_TYPE = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml'].freeze
  4. before_action do
  5. ActiveStorage::Current.host = request.base_url
  6. end
  7. def index
  8. assets = Asset.order('created_at DESC')
  9. @page = Page.find(params[:page_id]) if params[:page_id]
  10. @term = assets.ransack(params[:search] || '')
  11. assets = @term.result(distinct: true)
  12. @types = params[:filter] ? params[:filter].split(',') : []
  13. if @types.include?('all')
  14. params[:filter] = nil
  15. elsif @types.any?
  16. assets = assets.of_types(@types)
  17. end
  18. @assets = paginated? ? assets.paginate(pagination_parameters) : assets.all
  19. respond_to do |format|
  20. format.js do
  21. @page = Page.find_by_id(params[:page_id])
  22. render partial: 'asset_table', locals: { with_pagination: true }
  23. end
  24. format.html do
  25. render
  26. end
  27. end
  28. end
  29. def create
  30. @assets = []
  31. @page_attachments = []
  32. compress = current_site.try(:compress).nil? ? true : current_site.compress
  33. asset_params[:asset][:asset].reject(&:blank?).each do |uploaded_asset|
  34. if uploaded_asset.content_type == 'application/octet-stream'
  35. flash[:notice] = 'Please only upload assets that have a valid extension in the name.'
  36. else
  37. uploaded_asset = compress(uploaded_asset) if $kraken.api_key.present? && COMPRESS_FILE_TYPE.include?(uploaded_asset.content_type) && compress
  38. @asset = Asset.create(asset: uploaded_asset, caption: asset_params[:asset][:caption])
  39. if @asset.valid?
  40. set_owner_or_editor
  41. if params[:for_attachment]
  42. @page = Page.find_by_id(params[:page_id]) || Page.new
  43. @page_attachments << @page_attachment = @asset.page_attachments.build(page: @page)
  44. end
  45. @assets << @asset
  46. else
  47. error = @asset.errors.first.message
  48. flash[:error] = error
  49. end
  50. end
  51. end
  52. if asset_params[:for_attachment]
  53. render partial: 'admin/page_attachments/attachment', collection: @page_attachments
  54. else
  55. response_for :create
  56. end
  57. end
  58. def refresh
  59. if asset_params[:id]
  60. @asset = Asset.find(params[:id])
  61. @asset.asset.reprocess!
  62. flash[:notice] = t('clipped_extension.thumbnails_refreshed')
  63. redirect_to edit_admin_asset_path(@asset)
  64. else
  65. render
  66. end
  67. end
  68. private
  69. def compress(uploaded_asset)
  70. require 'open-uri'
  71. data = $kraken.upload(uploaded_asset.tempfile.path, 'lossy' => true)
  72. new_asset = data.success ? data.kraked_url : uploaded_asset.tempfile.path
  73. File.write(uploaded_asset.tempfile, URI.open(new_asset).read, mode: 'wb')
  74. uploaded_asset
  75. end
  76. def set_owner_or_editor
  77. @asset.created_by_id = current_user.id
  78. @asset.updated_by_id = current_user.id
  79. @asset.save! if @asset.id.present?
  80. end
  81. def asset_params
  82. params.permit(:id, :for_attachment, asset: [:for_attachment, { asset: [] }])
  83. end
  84. end

app/controllers/admin/configuration_controller.rb

0.0% lines covered

38 relevant lines. 0 lines covered and 38 lines missed.
    
  1. class Admin::ConfigurationController < ApplicationController
  2. # Admin::ConfigurationController handles the batch-updating of TrustyCms::Config entries.
  3. # It accepts any set of config name-value pairs but is accessible only to administrators.
  4. # Note that configuration is routed as a singular resource so we only deal with show/edit/update
  5. # and the show and edit views determine what set of config values is shown and made editable.
  6. before_action :initialize_config
  7. before_action :authorize_role
  8. only_allow_access_to :edit, :update,
  9. when: [:admin],
  10. denied_url: { controller: 'admin/configuration', action: 'show' },
  11. denied_message: 'You must have admin privileges to edit site configuration.'
  12. def show
  13. @user = current_user
  14. render
  15. end
  16. def edit
  17. render
  18. end
  19. def update
  20. if params[:trusty_config]
  21. begin
  22. TrustyCms.config.transaction do
  23. params[:trusty_config].each_pair do |key, value|
  24. @trusty_config[key] = TrustyCms::Config.find_or_initialize_by(key: key)
  25. @trusty_config[key].value = value # validation sets errors on @trusty_config['key'] that the helper methods will pick up
  26. end
  27. redirect_to action: :show
  28. end
  29. rescue ActiveRecord::RecordInvalid => e
  30. flash[:error] = 'Configuration error: please check the form'
  31. render action: :edit
  32. rescue TrustyCms::Config::ConfigError => e
  33. flash[:error] = "Configuration error: #{e}"
  34. render action: :edit
  35. end
  36. end
  37. end
  38. protected
  39. def initialize_config
  40. @trusty_config = {}
  41. end
  42. end

app/controllers/admin/extensions_controller.rb

0.0% lines covered

11 relevant lines. 0 lines covered and 11 lines missed.
    
  1. class Admin::ExtensionsController < ApplicationController
  2. before_action :authorize_role
  3. only_allow_access_to :index,
  4. when: :admin,
  5. denied_url: { controller: 'pages', action: 'index' },
  6. denied_message: 'You must have administrative privileges to perform this action.'
  7. def index
  8. @template_name = 'index' # for Admin::RegionsHelper
  9. @extensions = TrustyCms::Extension.descendants.sort_by { |e| e.extension_name }
  10. end
  11. end

app/controllers/admin/layouts_controller.rb

0.0% lines covered

8 relevant lines. 0 lines covered and 8 lines missed.
    
  1. class Admin::LayoutsController < Admin::ResourceController
  2. paginate_models
  3. before_action :authorize_role
  4. only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
  5. when: %i[designer admin],
  6. denied_url: { controller: 'admin/pages', action: 'index' },
  7. denied_message: 'You must have at least editor privileges to perform this action.'
  8. end

app/controllers/admin/page_attachments_controller.rb

0.0% lines covered

19 relevant lines. 0 lines covered and 19 lines missed.
    
  1. class Admin::PageAttachmentsController < Admin::ResourceController
  2. helper 'admin/assets'
  3. def new
  4. render partial: 'attachment', object: model
  5. end
  6. def load_model
  7. begin
  8. @asset = Asset.find(params[:asset_id])
  9. @page = page_attachment_params[:page_id].blank? ? Page.new : Page.find_by_id(page_attachment_params[:page_id])
  10. rescue ActiveRecord::RecordNotFound
  11. render nothing: true, layout: false
  12. end
  13. self.model = PageAttachment.new(asset: @asset, page: @page)
  14. end
  15. private
  16. def page_attachment_params
  17. params.permit(:asset_id, :page_id)
  18. end
  19. end

app/controllers/admin/page_fields_controller.rb

0.0% lines covered

13 relevant lines. 0 lines covered and 13 lines missed.
    
  1. class Admin::PageFieldsController < Admin::ResourceController
  2. def create
  3. model.attributes = page_fields_params
  4. @controller_name = 'page'
  5. @template_name = 'edit'
  6. render partial: 'page_field', object: model,
  7. locals: { page_field_counter: params[:page_field_counter].to_i }
  8. end
  9. private
  10. def page_fields_params
  11. params.require(:page_field).permit(:name, :content, :page_id)
  12. end
  13. end

app/controllers/admin/page_parts_controller.rb

0.0% lines covered

13 relevant lines. 0 lines covered and 13 lines missed.
    
  1. class Admin::PagePartsController < Admin::ResourceController
  2. def create
  3. model.attributes = page_parts_params
  4. @controller_name = 'page'
  5. @template_name = 'edit'
  6. render partial: 'page_part', object: model,
  7. locals: { page_part_counter: params[:index].to_i }
  8. end
  9. private
  10. def page_parts_params
  11. params.require(:page_part).permit(:name, :filter_id, :content)
  12. end
  13. end

app/controllers/admin/pages_controller.rb

0.0% lines covered

152 relevant lines. 0 lines covered and 152 lines missed.
    
  1. class Admin::PagesController < Admin::ResourceController
  2. before_action :initialize_meta_rows_and_buttons, only: %i[new edit create update]
  3. before_action :count_deleted_pages, only: [:destroy]
  4. before_action :set_page, only: %i[edit restore]
  5. rescue_from ActiveRecord::RecordInvalid, with: :validation_error
  6. class PreviewStop < ActiveRecord::Rollback
  7. def message
  8. 'Changes not saved!'
  9. end
  10. end
  11. create_responses do |r|
  12. r.plural.js do
  13. @level = params[:level].to_i
  14. @index = params[:index].to_i
  15. @rendered_html = ''
  16. @template_name = 'index'
  17. self.models = Page.find(params[:page_id]).children.all
  18. response.headers['Content-Type'] = 'text/html;charset=utf-8'
  19. render action: 'children', layout: false
  20. end
  21. end
  22. def index
  23. @site ||= Page.current_site
  24. @homepage ||= @site.homepage if @site
  25. @homepage ||= Page.homepage
  26. @site_id ||= @site.id
  27. @q = Page.ransack(params[:search] || '')
  28. response_for :plural
  29. end
  30. def search
  31. @site_id = params[:site_id] || Page.current_site.id
  32. @q = Page.ransack(params[:search])
  33. if params.dig(:search, :title).present?
  34. @title = params[:search][:title]
  35. @pages = Page.ransack(title_cont: @title, site_id_eq: @site_id).result
  36. else
  37. @pages = nil
  38. end
  39. render
  40. end
  41. def new
  42. assets = Asset.order('created_at DESC')
  43. @term = assets.ransack(params[:search] || '')
  44. @page = self.model = model_class.new_with_defaults(trusty_config)
  45. assign_page_attributes
  46. response_for :new
  47. end
  48. def edit
  49. assets = Asset.order('created_at DESC')
  50. @term = assets.ransack(params[:search] || '')
  51. @term.result(distinct: true)
  52. @versions = format_versions(@page.versions)
  53. response_for :edit
  54. end
  55. def restore
  56. index = params[:version_index].to_i
  57. restore_page_version(@page, index)
  58. redirect_to edit_admin_page_path(@page)
  59. end
  60. def preview
  61. render_preview
  62. rescue PreviewStop => e
  63. render text: e.message unless @performed_render
  64. end
  65. def save_table_position
  66. new_position = params[:new_position]
  67. Page.save_order(new_position)
  68. head :ok
  69. end
  70. private
  71. def set_page
  72. @page = Page.find(params[:id])
  73. end
  74. def validation_error(e)
  75. flash[:error] = e.message
  76. render :new
  77. end
  78. def assign_page_attributes
  79. if params[:page_id].blank?
  80. model.slug = '/'
  81. end
  82. model.parent_id = params[:page_id]
  83. end
  84. def format_versions(versions)
  85. return nil unless versions.any?
  86. versions
  87. .sort_by(&:created_at).reverse
  88. .map do |version|
  89. {
  90. index: version&.index,
  91. update_date: version&.created_at&.strftime('%B %d, %Y'),
  92. update_time: version&.created_at&.strftime('%I:%M %p'),
  93. updated_by: User.unscoped.find_by(id: version&.whodunnit)&.name || 'Unknown User',
  94. }
  95. end
  96. end
  97. def restore_page_version(page, index)
  98. lock_version = page.lock_version
  99. restored_page = page.versions[index].reify(has_many: true)
  100. restored_page.lock_version = lock_version
  101. restored_page.save!
  102. end
  103. def model_class
  104. if Page.descendants.any? { |d| d.to_s == params[:page_class] }
  105. verify_page_class(params[:page_class])
  106. elsif params[:page_id]
  107. Page.find(params[:page_id]).children
  108. else
  109. Page
  110. end
  111. end
  112. def render_preview
  113. params.permit!
  114. Page.transaction do
  115. page_class = Page.descendants.include?(model_class) ? model_class : Page
  116. if request.referer =~ %r{/admin/pages/(\d+)/edit}
  117. page = Page.find($1).becomes(page_class)
  118. layout_id = page.layout_id
  119. page.update(params[:page])
  120. page.published_at ||= Time.now
  121. else
  122. page = page_class.new(params[:page])
  123. page.published_at = page.updated_at = page.created_at = Time.now
  124. page.parent = Page.find($1) if request.referer =~ %r{/admin/pages/(\d+)/children/new}
  125. end
  126. page.pagination_parameters = pagination_parameters
  127. process_with_exception(page)
  128. end
  129. end
  130. def process_with_exception(page)
  131. page.process(request, response)
  132. @performed_render = true
  133. render template: 'site/show_page', layout: false
  134. raise PreviewStop
  135. end
  136. def count_deleted_pages
  137. @count = model.children.count + 1
  138. end
  139. def initialize_meta_rows_and_buttons
  140. @buttons_partials ||= []
  141. @meta ||= []
  142. @meta << { field: 'slug', type: 'text_field', args: [{ class: 'textbox' }] }
  143. @meta << { field: 'breadcrumb', type: 'text_field', args: [{ class: 'textbox' }] }
  144. end
  145. def verify_page_class(page_class)
  146. if page_class.constantize.ancestors.include?(Page)
  147. page_class.constantize
  148. else
  149. raise "I'm not allowed to constantize #{page_class}!"
  150. end
  151. end
  152. end

app/controllers/admin/preferences_controller.rb

0.0% lines covered

27 relevant lines. 0 lines covered and 27 lines missed.
    
  1. class Admin::PreferencesController < ApplicationController
  2. before_action :initialize_variables
  3. def show
  4. set_standard_body_style
  5. render :edit
  6. end
  7. def edit
  8. render
  9. end
  10. def update
  11. if @user.update(preferences_params)
  12. redirect_to admin_configuration_path
  13. else
  14. flash[:error] = t('preferences_controller.error_updating')
  15. render :edit
  16. end
  17. end
  18. private
  19. def initialize_variables
  20. @user = current_user
  21. @controller_name = 'user'
  22. @template_name = 'preferences'
  23. end
  24. def preferences_params
  25. params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :locale)
  26. end
  27. end

app/controllers/admin/references_controller.rb

0.0% lines covered

12 relevant lines. 0 lines covered and 12 lines missed.
    
  1. class Admin::ReferencesController < ApplicationController
  2. def show
  3. respond_to do |format|
  4. render_allowed_type(params[:type])
  5. format.any { render action: @type, content_type: 'text/html', layout: false }
  6. end
  7. end
  8. private
  9. def render_allowed_type(type)
  10. @type = type
  11. end
  12. end

app/controllers/admin/resource_controller.rb

0.0% lines covered

187 relevant lines. 0 lines covered and 187 lines missed.
    
  1. require 'trusty_cms/resource_responses'
  2. class Admin::ResourceController < ApplicationController
  3. extend TrustyCms::ResourceResponses
  4. helper_method :model, :current_object, :models, :current_objects, :model_symbol, :plural_model_symbol, :model_class, :model_name, :plural_model_name
  5. before_action :populate_format
  6. before_action :never_cache
  7. before_action :load_models, only: :index
  8. before_action :load_model, only: %i[new create edit update remove destroy]
  9. before_action :set_owner_or_editor, only: %i[new create update]
  10. after_action :clear_model_cache, only: %i[create update destroy]
  11. cattr_reader :paginated
  12. cattr_accessor :default_per_page, :will_paginate_options
  13. create_responses do |r|
  14. # Equivalent respond_to block for :plural responses:
  15. # respond_to do |wants|
  16. # wants.xml { render :xml => models }
  17. # wants.json { render :json => models }
  18. # wants.any
  19. # end
  20. r.plural.publish(:xml, :json) { render format_symbol => models }
  21. r.singular.publish(:xml, :json) { render format_symbol => model }
  22. r.singular.default { redirect_to edit_model_path if action_name == 'show' }
  23. r.not_found.publish(:xml, :json) { head :not_found }
  24. r.not_found.default { announce_not_found; redirect_to action: 'index' }
  25. r.invalid.publish(:xml, :json) { render format_symbol => model.errors, :status => :unprocessable_entity }
  26. r.invalid.default { announce_validation_errors; render action: template_name }
  27. r.stale.publish(:xml, :json) { head :conflict }
  28. r.stale.default { announce_update_conflict; render action: template_name }
  29. r.create.publish(:xml, :json) { render format_symbol => model, :status => :created, :location => url_for(format: format_symbol, id: model) }
  30. r.create.default { redirect_to continue_url(params) }
  31. r.update.publish(:xml, :json) { head :ok }
  32. r.update.default { redirect_to continue_url(params) }
  33. r.destroy.publish(:xml, :json) { head :deleted }
  34. r.destroy.default { redirect_to continue_url(params) }
  35. end
  36. def index
  37. response_for :plural
  38. end
  39. %i[show new edit remove].each do |action|
  40. class_eval %{
  41. def #{action} # def show
  42. response_for :singular # response_for :singular
  43. end # end
  44. }, __FILE__, __LINE__
  45. end
  46. %i[create update].each do |action|
  47. class_eval %{
  48. def #{action} # def create
  49. model.update!(permitted_params[model_symbol]) # model.update!(params[model_symbol])
  50. response_for :#{action} # response_for :create
  51. end # end
  52. }, __FILE__, __LINE__
  53. end
  54. def destroy
  55. model.destroy
  56. response_for :destroy
  57. end
  58. def self.model_class(model_class = nil)
  59. @model_class ||= (model_class || controller_name).to_s.singularize.camelize.constantize
  60. end
  61. # call paginate_models to declare that will_paginate should be used in the index view
  62. # options specified here are accessible in the view by calling will_paginate_options
  63. # eg.
  64. #
  65. # Class MyController < Admin::ResourceController
  66. # paginate_models :per_page => 100
  67. def self.paginate_models(options = {})
  68. @@paginated = true
  69. @@will_paginate_options = options.slice(:class, :previous_label, :next_label, :inner_window, :outer_window, :separator, :container).merge(param_name: :p)
  70. @@default_per_page = options[:per_page]
  71. end
  72. # returns a hash of options that can be passed to will_paginate
  73. # the @pagination_for@ helper method calls @will_paginate_options@ unless other options are supplied.
  74. #
  75. # pagination_for(@events)
  76. def will_paginate_options
  77. self.class.will_paginate_options || {}
  78. end
  79. helper_method :will_paginate_options
  80. # a convenience method that returns true if paginate_models has been called on this controller class
  81. # and can be used to make display decisions in controller and view
  82. def paginated?
  83. self.class.paginated == true && params[:pp] != 'all'
  84. end
  85. helper_method :paginated?
  86. # return a hash of page and per_page that can be used to build a will_paginate collection
  87. # the per_page figure can be set in several ways:
  88. # request parameter > declared by paginate_models > default set in config entry @admin.pagination.per_page@ > overall default of 50
  89. def pagination_parameters
  90. pp = params[:pp] || TrustyCms.config['admin.pagination.per_page']
  91. pp = (self.class.default_per_page || 50) if pp.blank?
  92. {
  93. page: (params[:p] || 1).to_i,
  94. per_page: pp.to_i,
  95. }
  96. end
  97. protected
  98. def rescue_action(exception)
  99. case exception
  100. when ActiveRecord::RecordInvalid
  101. response_for :invalid
  102. when ActiveRecord::StaleObjectError
  103. response_for :stale
  104. when ActiveRecord::RecordNotFound
  105. response_for :not_found
  106. else
  107. super
  108. end
  109. end
  110. def model_class
  111. self.class.model_class
  112. end
  113. def set_owner_or_editor
  114. if model.has_attribute? :created_by_id
  115. model.created_by_id = current_user.id if model.id == nil
  116. model.updated_by_id = current_user.id
  117. end
  118. end
  119. def model
  120. instance_variable_get("@#{model_symbol}") || load_model
  121. end
  122. alias :current_object :model
  123. def model=(object)
  124. instance_variable_set("@#{model_symbol}", object)
  125. end
  126. def load_model
  127. self.model = if params[:id]
  128. model_class.find(params[:id])
  129. else
  130. model_class.new
  131. end
  132. end
  133. def models
  134. instance_variable_get("@#{plural_model_symbol}") || load_models
  135. end
  136. alias :current_objects :models
  137. def models=(objects)
  138. instance_variable_set("@#{plural_model_symbol}", objects)
  139. end
  140. def load_models
  141. self.models = paginated? ? model_class.paginate(pagination_parameters) : model_class.all
  142. end
  143. def model_name
  144. model_class.name
  145. end
  146. def plural_model_name
  147. model_name.pluralize
  148. end
  149. alias :models_name :plural_model_name
  150. def model_symbol
  151. model_name.underscore.intern
  152. end
  153. def plural_model_symbol
  154. model_name.pluralize.underscore.intern
  155. end
  156. alias :models_symbol :plural_model_symbol
  157. def humanized_model_name
  158. t(model_name.underscore.downcase)
  159. end
  160. def continue_url(options)
  161. options[:redirect_to] || (params[:continue] ? { action: 'edit', id: model.id } : index_page_for_model)
  162. end
  163. def index_page_for_model
  164. parts = { action: 'index' }
  165. if paginated? && model && i = model_class.all.index(model)
  166. p = (i / pagination_parameters[:per_page].to_i) + 1
  167. parts[:p] = p if p && p > 1
  168. end
  169. parts
  170. end
  171. def edit_model_path
  172. method = "edit_admin_#{model_name.underscore}_path"
  173. send method.to_sym, params[:id]
  174. end
  175. def announce_validation_errors
  176. flash.now[:error] = t('resource_controller.validation_errors')
  177. end
  178. def announce_not_found
  179. flash[:notice] = t('resource_controller.not_found', humanized_model_name: humanized_model_name)
  180. end
  181. def announce_update_conflict
  182. flash.now[:error] = t('resource_controller.update_conflict', humanized_model_name: humanized_model_name)
  183. end
  184. def clear_model_cache
  185. Rails.cache.clear
  186. end
  187. def format_symbol
  188. format.to_sym
  189. end
  190. def format
  191. params[:format] || 'html'
  192. end
  193. # I would like to set this to expires_in(1.minute, :private => true) to allow for more fluid navigation
  194. # but the annoyance for concurrent authors would be too great.
  195. def never_cache
  196. expires_now
  197. end
  198. # Assist with user agents that cause improper content-negotiation
  199. # warn "Remove default HTML format, Accept header no longer used. (#{__FILE__}: #{__LINE__})" if Rails.version !~ /^2\.1/
  200. def populate_format
  201. params[:format] ||= 'html' unless request.xhr?
  202. end
  203. def permitted_params
  204. model_symbols = ActiveRecord::Base.descendants.map { |a| a.name.underscore.to_sym }
  205. keys = params.keys.map { |k| k.underscore.to_sym }
  206. valid_symbols = model_symbols & keys
  207. valid_symbols.each do |symbol|
  208. params[symbol].permit!
  209. end
  210. params
  211. end
  212. end

app/controllers/admin/sites_controller.rb

0.0% lines covered

14 relevant lines. 0 lines covered and 14 lines missed.
    
  1. class Admin::SitesController < Admin::ResourceController
  2. helper :sites
  3. before_action :authorize_role
  4. only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
  5. when: :admin,
  6. denied_url: { controller: 'pages', action: 'index' },
  7. denied_message: 'You must have administrative privileges to perform this action.'
  8. %w(move_higher move_lower move_to_top move_to_bottom).each do |action|
  9. define_method action do
  10. model.send(action)
  11. response_for :update
  12. end
  13. end
  14. end

app/controllers/admin/snippets_controller.rb

0.0% lines covered

8 relevant lines. 0 lines covered and 8 lines missed.
    
  1. class Admin::SnippetsController < Admin::ResourceController
  2. paginate_models
  3. before_action :authorize_role
  4. only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
  5. when: %i[designer admin],
  6. denied_url: { controller: 'admin/pages', action: 'index' },
  7. denied_message: 'You must have at least editor privileges to perform this action.'
  8. end

app/controllers/admin/users_controller.rb

37.14% lines covered

35 relevant lines. 13 lines covered and 22 lines missed.
    
  1. 1 class Admin::UsersController < Admin::ResourceController
  2. 1 paginate_models
  3. 1 before_action :authorize_role
  4. 1 only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
  5. when: :admin,
  6. denied_url: { controller: 'pages', action: 'index' },
  7. denied_message: 'You must have administrative privileges to perform this action.'
  8. 1 before_action :ensure_deletable, only: %i[remove destroy]
  9. 1 def show
  10. redirect_to edit_admin_user_path(params[:id])
  11. end
  12. 1 def create
  13. user = User.new(user_params)
  14. if user.save
  15. flash[:notice] = 'User was created.'
  16. redirect_to admin_users_path
  17. else
  18. flash[:error] = 'There was an error saving the user. Please try again.'
  19. render :new
  20. end
  21. end
  22. 1 def update
  23. user_params = params[model_symbol].permit!
  24. if user_params && user_params['admin'] == false && model == current_user
  25. user_params.delete('admin')
  26. announce_cannot_remove_self_from_admin_role
  27. end
  28. model.skip_password_validation = true unless user_params[:password_confirmation].present?
  29. if model.update(user_params)
  30. response_for :update
  31. else
  32. flash[:error] = 'There was an error saving the user. Please try again.'
  33. render :edit
  34. end
  35. end
  36. 1 def ensure_deletable
  37. if current_user.id.to_s == params[:id].to_s
  38. announce_cannot_delete_self
  39. redirect_to admin_users_path
  40. end
  41. end
  42. 1 private
  43. 1 def user_params
  44. params.require(:user).permit(:first_name, :last_name, :admin, :designer,
  45. :password, :password_confirmation, :email, :site_id, :notes, site_ids: [])
  46. end
  47. 1 def announce_cannot_delete_self
  48. flash[:error] = t('users_controller.cannot_delete_self')
  49. end
  50. 1 def announce_cannot_remove_self_from_admin_role
  51. flash[:error] = 'You cannot remove yourself from the admin role.'
  52. end
  53. end

app/controllers/application_controller.rb

0.0% lines covered

75 relevant lines. 0 lines covered and 75 lines missed.
    
  1. require 'login_system'
  2. class ApplicationController < ActionController::Base
  3. include LoginSystem
  4. prepend_view_path("#{TRUSTY_CMS_ROOT}/app/views")
  5. protect_from_forgery with: :exception
  6. before_action :authenticate_user!
  7. before_action :set_timezone
  8. before_action :set_user_locale
  9. before_action :set_javascripts_and_stylesheets
  10. before_action :force_utf8_params if RUBY_VERSION =~ /1\.9/
  11. before_action :set_standard_body_style, only: %i[new edit update create]
  12. before_action :set_mailer
  13. before_action :set_paper_trail_whodunnit
  14. attr_accessor :trusty_config, :cache
  15. attr_reader :pagination_parameters
  16. helper_method :pagination_parameters
  17. def initialize
  18. super
  19. @trusty_config = TrustyCms::Config
  20. end
  21. def after_sign_in_path_for(_resource)
  22. admin_pages_path
  23. end
  24. def template_name
  25. case action_name
  26. when 'index'
  27. 'index'
  28. when 'new', 'create'
  29. 'new'
  30. when 'show'
  31. 'show'
  32. when 'edit', 'update'
  33. 'edit'
  34. when 'remove', 'destroy'
  35. 'remove'
  36. else
  37. action_name
  38. end
  39. end
  40. private
  41. def set_mailer
  42. ActionMailer::Base.default_url_options[:host] = request.host_with_port
  43. end
  44. def set_user_locale
  45. I18n.locale = current_user && !current_user.locale.blank? ? current_user.locale : TrustyCms::Config['default_locale']
  46. end
  47. def set_timezone
  48. Time.zone = !TrustyCms::Config['local.timezone'].nil? && TrustyCms::Config['local.timezone'].empty? ? Time.zone_default : TrustyCms::Config['local.timezone']
  49. end
  50. def set_javascripts_and_stylesheets
  51. @stylesheets ||= []
  52. @stylesheets.concat %w(admin/main)
  53. @javascripts ||= []
  54. end
  55. def set_standard_body_style
  56. @body_classes ||= []
  57. @body_classes.concat(%w(reversed))
  58. end
  59. # When using TrustyCms with Ruby 1.9, the strings that come in from forms are ASCII-8BIT encoded.
  60. # That causes problems, especially when using special chars and with certain DBs, like DB2
  61. # That's why we force the encoding of the params to UTF-8
  62. # That's what's happening in Rails 3, too: https://github.com/rails/rails/commit/25215d7285db10e2c04d903f251b791342e4dd6a
  63. #
  64. # See http://stackoverflow.com/questions/8268778/rails-2-3-9-encoding-of-query-parameters
  65. # See https://rails.lighthouseapp.com/projects/8994/tickets/4807
  66. # See http://jasoncodes.com/posts/ruby19-rails2-encodings (thanks for the following code, Jason!)
  67. def force_utf8_params
  68. traverse = lambda do |object, block|
  69. if object.is_a?(Hash)
  70. object.each_value { |o| traverse.call(o, block) }
  71. elsif object.is_a?(Array)
  72. object.each { |o| traverse.call(o, block) }
  73. else
  74. block.call(object)
  75. end
  76. object
  77. end
  78. force_encoding = lambda do |o|
  79. o.force_encoding(Encoding::UTF_8) if o.respond_to?(:force_encoding)
  80. end
  81. traverse.call(params, force_encoding)
  82. end
  83. end

app/controllers/page_status_controller.rb

0.0% lines covered

50 relevant lines. 0 lines covered and 50 lines missed.
    
  1. class PageStatusController < ApplicationController
  2. skip_before_action :verify_authenticity_token, only: [:refresh]
  3. skip_before_action :authenticate_user!, only: [:refresh]
  4. before_action :authenticate_bearer_token
  5. def refresh
  6. pages = Page.where(status_id: Status[:scheduled].id)
  7. updated_pages, remaining_pages = process_pages(pages)
  8. render json: refresh_response(updated_pages, remaining_pages), status: :ok
  9. end
  10. private
  11. def authenticate_bearer_token
  12. provided_token = request.headers['Authorization']&.split(' ')&.last
  13. expected_token = Rails.application.credentials[:trusty_cms][:page_status_bearer_token]
  14. if provided_token.blank?
  15. render json: { error: 'Missing Bearer Token' }, status: :unauthorized and return
  16. end
  17. unless ActiveSupport::SecurityUtils.secure_compare(provided_token, expected_token)
  18. render json: { error: 'Invalid Bearer Token' }, status: :unauthorized
  19. end
  20. end
  21. def process_pages(pages)
  22. updated_pages = []
  23. remaining_pages = []
  24. pages.each do |page|
  25. page_id = page.id
  26. if page.published_at <= Time.now
  27. page.update(status_id: Status[:published].id)
  28. updated_pages << page_id
  29. else
  30. remaining_pages << page_id
  31. end
  32. end
  33. [updated_pages, remaining_pages]
  34. end
  35. def refresh_response(updated_pages, remaining_pages)
  36. if updated_pages.any?
  37. updated_pages_count = updated_pages.count
  38. {
  39. message: "Successfully updated status of #{updated_pages_count} #{'page'.pluralize(updated_pages_count)}.",
  40. updated_page_ids: updated_pages,
  41. remaining_scheduled_page_ids: remaining_pages,
  42. }
  43. else
  44. {
  45. message: 'No scheduled pages matched the criteria for status refresh.',
  46. remaining_scheduled_page_ids: remaining_pages,
  47. }
  48. end
  49. end
  50. end

app/controllers/site_controller.rb

0.0% lines covered

67 relevant lines. 0 lines covered and 67 lines missed.
    
  1. require 'trusty_cms/pagination/controller'
  2. require 'will_paginate/array'
  3. class SiteController < ApplicationController
  4. include TrustyCms::Pagination::Controller
  5. # no_login_required
  6. skip_before_action :authenticate_user!
  7. def self.cache_timeout=(val)
  8. TrustyCms::PageResponseCacheDirector.cache_timeout = val
  9. end
  10. def self.cache_timeout
  11. TrustyCms::PageResponseCacheDirector.cache_timeout
  12. end
  13. def show_page
  14. url = params[:url]
  15. url = if Array === url
  16. url.join('/')
  17. else
  18. url.to_s
  19. end
  20. if @page = find_page(url)
  21. # This is a bit of a hack to get Vanity URL pages working in another extension
  22. # In Rails 2, redirect_to halted execution, so process_page could be aliased and
  23. # a redirect could be used. This no longer works. There's a better fix for this,
  24. # but for now, anything that aliases process_page can return false if it's rendering
  25. # or redirecting on its own.
  26. return unless process_page(@page)
  27. set_cache_control
  28. @performed_render ||= true
  29. render layout: false
  30. else
  31. render template: 'site/not_found', status: 404, layout: false
  32. end
  33. rescue Page::MissingRootPageError
  34. redirect_to welcome_path
  35. end
  36. def cacheable_request?
  37. (request.head? || request.get?) && live?
  38. end
  39. # hide_action :cacheable_request?
  40. def set_expiry(time, options = {})
  41. expires_in time, options
  42. end
  43. # hide_action :set_expiry
  44. def set_etag(val)
  45. headers['ETag'] = val
  46. end
  47. # hide_action :set_expiry
  48. private
  49. def set_cache_control
  50. response_cache_director(@page).set_cache_control
  51. end
  52. def response_cache_director(page)
  53. klass_name = "TrustyCms::#{page.class}ResponseCacheDirector"
  54. begin
  55. klass = klass_name.constantize
  56. rescue NameError, LoadError
  57. director_klass = 'TrustyCms::PageResponseCacheDirector'
  58. # Rubocop: The use of eval is a serious security risk.
  59. # eval(%Q{class #{klass_name} < #{director_klass}; end}, TOPLEVEL_BINDING)
  60. klass = director_klass.constantize
  61. end
  62. klass.new(page, self)
  63. end
  64. def find_page(url)
  65. found = Page.find_by_path(url, live?)
  66. found if found && (found.published? || dev?)
  67. end
  68. def process_page(page)
  69. page.pagination_parameters = pagination_parameters
  70. page.process(request, response)
  71. end
  72. def dev?
  73. request.host == @trusty_config['dev.host'] || request.host =~ /^dev\./
  74. end
  75. def live?
  76. not dev?
  77. end
  78. end

app/controllers/social_mailer_controller.rb

0.0% lines covered

23 relevant lines. 0 lines covered and 23 lines missed.
    
  1. class SocialMailerController < ApplicationController
  2. include ShareLayouts::Controllers::ActionController
  3. trusty_layout 'default', { only: :create_social_mail }
  4. # no_login_required
  5. skip_before_action :authenticate_user!
  6. def create_social_mail
  7. mailer_options = {
  8. to: params[:to],
  9. from: params[:from],
  10. from_name: params[:from_name],
  11. message: params[:message],
  12. subject: params[:subject],
  13. }
  14. end
  15. def social_mail_form
  16. render template: 'rad_social_mailer/social_mail_form',
  17. layout: false,
  18. locals: {
  19. email_message: params[:email_message],
  20. email_subject: params[:email_subject],
  21. email_action_url: params[:email_action_url],
  22. }
  23. end
  24. end

app/helpers/admin/configuration_helper.rb

0.0% lines covered

54 relevant lines. 0 lines covered and 54 lines missed.
    
  1. module Admin::ConfigurationHelper
  2. # Defines helper methods for use in the admin interface when displaying or editing configuration.
  3. # Renders the setting as label and value:
  4. #
  5. # show_config("admin.title")
  6. # => <label for="admin_title">Admin title<label><span id="admin_title">TrustyCms CMS</span>
  7. #
  8. def show_config(key, options = {})
  9. setting = setting_for(key)
  10. setting.valid?
  11. domkey = key.gsub(/\W/, '_')
  12. html = ''
  13. html << content_tag(:label, t("trusty_config.#{key}").titlecase, for: domkey)
  14. if setting.boolean?
  15. value = setting.checked? ? t('yes') : t('no')
  16. html << content_tag(:span, value, id: domkey, class: "#{value} #{options[:class]}")
  17. else
  18. value = setting.selected_value || setting.value
  19. html << content_tag(:span, value, id: domkey, class: options[:class])
  20. end
  21. html << content_tag(:span, " #{t("units.#{setting.units}")}", class: 'units') if setting.units
  22. html << content_tag(:span, " #{t('warning')}: #{[setting.errors[:value]].flatten.first}", class: 'warning') if setting.errors.messages[:value].present?
  23. Rails.logger.error(html)
  24. html.html_safe
  25. end
  26. # Renders the setting as label and appropriate input field:
  27. #
  28. # edit_setting("admin.title")
  29. # => <label for="admin_title">Admin title<label><input type="text" name="config['admin.title']" id="admin_title" value="TrustyCms CMS" />
  30. #
  31. # edit_config("defaults.page.status")
  32. # =>
  33. # <label for="defaults_page_status">Default page status<label>
  34. # <select type="text" name="config['defaults.page.status']" id="defaults_page_status">
  35. # <option value="Draft">Draft</option>
  36. # ...
  37. # </select>
  38. #
  39. # edit_setting("user.allow_password_reset?")
  40. # => <label for="user_allow_password_reset_">Admin title<label><input type="checkbox" name="config['user.allow_password_reset?']" id="user_allow_password_reset_" value="1" checked="checked" />
  41. #
  42. def edit_config(key, _options = {})
  43. setting = setting_for(key)
  44. domkey = key.gsub(/\W/, '_')
  45. name = "trusty_config[#{key}]"
  46. title = t("trusty_config.#{key}").titlecase
  47. title << content_tag(:span, " (#{t("units.#{setting.units}")})", class: 'units') if setting.units
  48. value = params[key.to_sym].nil? ? setting.value : params[key.to_sym]
  49. html = ''
  50. if setting.boolean?
  51. html << hidden_field_tag(name, 0)
  52. html << check_box_tag(name, 1, value, class: 'setting', id: domkey)
  53. html << content_tag(:label, title.html_safe, class: 'checkbox', for: domkey)
  54. elsif setting.selector?
  55. html << content_tag(:label, title.html_safe, for: domkey)
  56. html << select_tag(name, options_for_select(setting.definition.selection, value), class: 'setting', id: domkey)
  57. else
  58. html << content_tag(:label, title.html_safe, for: domkey)
  59. html << text_field_tag(name, value, class: 'textbox', id: domkey)
  60. end
  61. if setting.errors[:value].present?
  62. html << content_tag(:span, [setting.errors[:value]].flatten.first, class: 'error')
  63. html = content_tag(:span, html.html_safe, class: 'error-with-field')
  64. end
  65. html.html_safe
  66. end
  67. def setting_for(key)
  68. @trusty_config ||= {} # normally initialized in Admin::ConfigurationController
  69. @trusty_config[key] ||= TrustyCms.config.find_or_initialize_by(key: key)
  70. end
  71. def definition_for(key)
  72. if setting = setting_for(key)
  73. setting.definition
  74. end
  75. end
  76. end

app/helpers/admin/export_helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module Admin::ExportHelper
  2. end

app/helpers/admin/extensions_helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module Admin::ExtensionsHelper
  2. end

app/helpers/admin/layouts_helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module Admin::LayoutsHelper
  2. end

app/helpers/admin/node_helper.rb

0.0% lines covered

94 relevant lines. 0 lines covered and 94 lines missed.
    
  1. module Admin::NodeHelper
  2. def render_nodes(page, starting_index, parent_index = nil, simple = false)
  3. @rendered_html = ''
  4. render_node page, starting_index, parent_index, simple
  5. @rendered_html
  6. end
  7. def render_node(page, index, parent_index = nil, simple = false)
  8. @current_node = prepare_page(page)
  9. @rendered_html += render_partial(page, index: index, parent_index: parent_index, simple: simple)
  10. index
  11. end
  12. def render_search_node(page)
  13. @current_node = prepare_page(page)
  14. @rendered_html = render_partial(page, index: 0, parent_index: nil, simple: false)
  15. end
  16. def prepare_page(page)
  17. page.extend MenuRenderer
  18. page.view = self
  19. if page.additional_menu_features?
  20. page.extend(*page.menu_renderer_modules)
  21. end
  22. page
  23. end
  24. def homepage
  25. @homepage ||= Page.find_by_parent_id(nil)
  26. end
  27. def show_all?
  28. controller.action_name == 'remove'
  29. end
  30. def expanded_rows
  31. unless @expanded_rows
  32. @expanded_rows = if rows = cookies[:expanded_rows]
  33. rows.split(',').map do |x|
  34. begin
  35. Integer(x)
  36. rescue StandardError
  37. nil
  38. end
  39. end .compact
  40. else
  41. []
  42. end
  43. if homepage && !@expanded_rows.include?(homepage.id)
  44. @expanded_rows << homepage.id
  45. end
  46. end
  47. @expanded_rows
  48. end
  49. def expanded
  50. show_all? || expanded_rows.include?(@current_node.id)
  51. end
  52. def expander(level)
  53. if @current_node.children.empty? || (level == 0)
  54. ''
  55. else
  56. image((expanded ? 'collapse' : 'expand'),
  57. class: 'expander', alt: 'toggle children',
  58. title: '')
  59. end
  60. end
  61. def icon
  62. icon_name = @current_node.virtual? ? 'virtual_page' : 'page'
  63. image(icon_name, class: 'icon', alt: '', title: '')
  64. end
  65. def node_title
  66. %{<span class="title">#{h(@current_node.title)}</span>}.html_safe
  67. end
  68. def page_type
  69. display_name = @current_node.class.display_name
  70. if display_name == 'Page'
  71. ''
  72. else
  73. %{<span class="info">(#{h(display_name)})</span>}.html_safe
  74. end
  75. end
  76. def spinner
  77. image('spinner.gif',
  78. class: 'busy', id: "busy_#{@current_node.id}",
  79. alt: '', title: '',
  80. style: 'display: none;')
  81. end
  82. private
  83. def render_partial(page, index:, parent_index:, simple:)
  84. render partial: 'admin/pages/node',
  85. locals: {
  86. level: index,
  87. index: index,
  88. parent_index: parent_index,
  89. page: page,
  90. simple: simple,
  91. branch: page.children.count.positive?
  92. }
  93. end
  94. end

app/helpers/admin/page_attachments_helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module Admin::PageAttachmentsHelper
  2. end

app/helpers/admin/pages_helper.rb

0.0% lines covered

16 relevant lines. 0 lines covered and 16 lines missed.
    
  1. module Admin::PagesHelper
  2. include Admin::NodeHelper
  3. include Admin::ReferencesHelper
  4. def class_of_page
  5. @page.class
  6. end
  7. def filter
  8. @page.parts.first.filter if @page.parts.respond_to?(:any?) && @page.parts.any?
  9. end
  10. def meta_errors?
  11. !!(@page.errors[:slug] or @page.errors[:breadcrumb])
  12. end
  13. def clean_page_description(page)
  14. page.description.to_s.strip.gsub(/\t/, '').gsub(/\s+/, ' ')
  15. end
  16. end

app/helpers/admin/preferences_helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module Admin::PreferencesHelper
  2. end

app/helpers/admin/references_helper.rb

0.0% lines covered

40 relevant lines. 0 lines covered and 40 lines missed.
    
  1. require 'RedCloth'
  2. module Admin::ReferencesHelper
  3. def tag_reference
  4. String.new.tap do |output|
  5. class_of_page.tag_descriptions.sort.each do |tag_name, description|
  6. value = t("desc.#{tag_name.gsub(':', '-')}").match('desc') ? description : t("desc.#{tag_name.gsub(':', '-')}")
  7. output << render(partial: 'admin/references/tag_reference',
  8. locals: { tag_name: tag_name,
  9. description: RedCloth.new(TrustyCms::Taggable::Util.strip_leading_whitespace(value)).to_html })
  10. end
  11. end
  12. end
  13. def filter_reference
  14. if filter.blank?
  15. 'There is no filter on the current page part.'
  16. else
  17. if filter.description.blank?
  18. 'There is no documentation on this filter.'
  19. else
  20. filter.description
  21. end
  22. end
  23. end
  24. def _display_name
  25. case params[:type]
  26. when 'filters'
  27. filter ? filter.filter_name : t('select.none')
  28. when 'tags'
  29. class_of_page.display_name
  30. end
  31. end
  32. def filter
  33. @filter ||= begin
  34. TextFilter.find_descendant(params[:filter_name])
  35. end
  36. end
  37. def class_of_page
  38. @page_class ||= (params[:class_name].blank? ? 'Page' : params[:class_name]).constantize
  39. end
  40. end

app/helpers/admin/regions_helper.rb

0.0% lines covered

27 relevant lines. 0 lines covered and 27 lines missed.
    
  1. module Admin::RegionsHelper
  2. def render_region(region, options = {}, &block)
  3. lazy_initialize_region_set
  4. default_partials = TrustyCms::AdminUI::RegionPartials.new(self)
  5. if block_given?
  6. block.call(default_partials)
  7. (options[:locals] ||= {}).merge!(defaults: default_partials)
  8. end
  9. output = @region_set[region].compact.map do |partial|
  10. begin
  11. render options.merge(partial: partial)
  12. rescue ::ActionView::MissingTemplate # couldn't find template
  13. default_partials[partial]
  14. rescue ::ActionView::TemplateError => e # error in template
  15. raise e
  16. end
  17. end.join.html_safe
  18. # comment out all the html logging
  19. # Rails.logger.error(output)
  20. block_given? ? concat(output) : output
  21. end
  22. def lazy_initialize_region_set
  23. unless @region_set
  24. @controller_name ||= @_controller.controller_name
  25. @template_name ||= @_controller.template_name
  26. @region_set = admin.send(@controller_name).send(@template_name)
  27. end
  28. end
  29. end

app/helpers/admin/resource_helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module Admin::ResourceHelper
  2. end

app/helpers/admin/users_helper.rb

28.57% lines covered

7 relevant lines. 2 lines covered and 5 lines missed.
    
  1. 1 module Admin::UsersHelper
  2. 1 def roles(user)
  3. roles = []
  4. roles << I18n.t('admin') if user.admin?
  5. roles << I18n.t('editor') if user.editor?
  6. roles << I18n.t('content_editor') if user.content_editor?
  7. roles.join(', ')
  8. end
  9. end

app/helpers/admin/welcome_helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module Admin::WelcomeHelper
  2. end

app/helpers/application_helper.rb

0.0% lines covered

145 relevant lines. 0 lines covered and 145 lines missed.
    
  1. module ApplicationHelper
  2. include Admin::RegionsHelper
  3. def trusty_config
  4. TrustyCms::Config
  5. end
  6. def default_page_title
  7. title + ' - ' + subtitle
  8. end
  9. def title
  10. trusty_config['admin.title'] || 'Trusty CMS'
  11. end
  12. def subtitle
  13. trusty_config['admin.subtitle'] || 'Publishing for Small Teams'
  14. end
  15. def logged_in?
  16. !current_user.nil?
  17. end
  18. def onsubmit_status(model)
  19. model.new_record? ? t('creating_status', model: t(model.class.name.downcase)) : "#{I18n.t('saving_changes')}&#8230;"
  20. end
  21. def save_model_button(model, options = {})
  22. model_name = model.class.name.underscore
  23. human_model_name = model_name.humanize.titlecase
  24. options[:label] ||= model.new_record? ?
  25. t('buttons.create', name: t(model_name, default: human_model_name), default: 'Create ' + human_model_name) :
  26. t('buttons.save_changes', default: 'Save Changes')
  27. options[:class] ||= 'button'
  28. options[:accesskey] ||= 'S'
  29. options[:id] ||= 'save-button'
  30. submit_tag options.delete(:label), options
  31. end
  32. def save_model_and_continue_editing_button(_model)
  33. submit_tag t('buttons.save_and_continue'), name: 'continue', class: 'button', accesskey: 's', id: 'save-and-continue-button'
  34. end
  35. def current_item?(item)
  36. if item.tab&.many? { |i| current_url?(i.relative_url) }
  37. # Accept only stricter URL matches if more than one matches
  38. current_page?(item.url)
  39. else
  40. current_url?(item.relative_url)
  41. end
  42. end
  43. def current_tab?(tab)
  44. @current_tab ||= tab if tab.any? { |item| current_url?(item.relative_url) }
  45. @current_tab == tab
  46. end
  47. def current_url?(options)
  48. url = case options
  49. when Hash
  50. url_for options
  51. else
  52. options.to_s
  53. end
  54. request.original_fullpath =~ Regexp.new('^' + Regexp.quote(clean(url)))
  55. end
  56. def clean(url)
  57. uri = URI.parse(url)
  58. uri.path.gsub(%r{/+}, '/').gsub(%r{/$}, '')
  59. end
  60. def admin?
  61. current_user&.admin?
  62. end
  63. def designer?
  64. current_user and (current_user.designer? or current_user.admin?)
  65. end
  66. def updated_stamp(model)
  67. unless model.new_record?
  68. updated_by = (model.updated_by || model.created_by)
  69. name = updated_by ? updated_by.name : nil
  70. time = (model.updated_at || model.created_at)
  71. if name || time
  72. html = %{<div class="updated_line">#{t('timestamp.last_updated')} }
  73. html << %{#{t('timestamp.by')} <strong>#{name}</strong> } if name
  74. html << %{#{t('timestamp.at')} #{timestamp(time)}} if time
  75. html << %{</div>}
  76. html.html_safe
  77. end
  78. end
  79. end
  80. def timestamp(time)
  81. # time.strftime("%I:%M %p on %B %e, %Y").sub("AM", 'am').sub("PM", 'pm')
  82. I18n.localize(time, format: :timestamp)
  83. end
  84. def meta_errors?
  85. false
  86. end
  87. def meta_label
  88. meta_errors? ? 'Less' : 'More'
  89. end
  90. def image(name, options = {})
  91. image_tag(append_image_extension("admin/#{name}"), options)
  92. end
  93. def admin
  94. TrustyCms::AdminUI.instance
  95. end
  96. def body_classes
  97. @body_classes ||= []
  98. end
  99. def nav_tabs
  100. admin.nav
  101. end
  102. def translate_with_default(name)
  103. t(name.underscore.downcase, default: name)
  104. end
  105. def available_locales_select
  106. [[t('select.default'), '']] + TrustyCms::AvailableLocales.locales
  107. end
  108. def stylesheet_overrides
  109. overrides = []
  110. if File.exist?("#{Rails.root}/public/stylesheets/admin/overrides.css") || File.exist?("#{Rails.root}/public/stylesheets/sass/admin/overrides.sass")
  111. overrides << 'admin/overrides'
  112. end
  113. overrides
  114. end
  115. def javascript_overrides
  116. overrides = []
  117. if File.exist?("#{Rails.root}/public/javascripts/admin/overrides.js")
  118. overrides << 'admin/overrides'
  119. end
  120. overrides
  121. end
  122. # returns the usual set of pagination links.
  123. # options are passed through to will_paginate
  124. # and a 'show all' depagination link is added if relevant.
  125. def pagination_for(list, options = {})
  126. if list.respond_to? :total_pages
  127. options = {
  128. max_per_page: @trusty_config['pagination.max_per_page'] || 500,
  129. depaginate: true,
  130. }.merge(options.symbolize_keys)
  131. depaginate = options.delete(:depaginate) # supply :depaginate => false to omit the 'show all' link
  132. depagination_limit = options.delete(:max_per_page) # supply :max_per_page => false to include the 'show all' link no matter how large the collection
  133. html = will_paginate(list, will_paginate_options.merge(options))
  134. if depaginate && list.total_pages > 1 && (!depagination_limit.blank? || list.total_entries <= depagination_limit.to_i)
  135. html << content_tag(:div, link_to(t('show_all'), pp: 'all'), class: 'depaginate')
  136. elsif depaginate && list.total_entries > depagination_limit.to_i
  137. html = content_tag(:div, link_to('paginate', p: 1), class: 'pagination')
  138. end
  139. html
  140. end
  141. end
  142. private
  143. def append_image_extension(name)
  144. if name =~ /\.(.*?)$/
  145. name
  146. else
  147. name + '.png'
  148. end
  149. end
  150. end

app/helpers/rad_social_helper.rb

0.0% lines covered

18 relevant lines. 0 lines covered and 18 lines missed.
    
  1. module RadSocialHelper
  2. def rad_test_method
  3. 'SURPRISE SURPRISE SURPRISE'
  4. end
  5. def rad_share_widget(options)
  6. url = options[:url].nil? ? request.url : options[:url]
  7. message = options[:message].nil? ? "Check out #{options[:title]}." : options[:message]
  8. email_subject = options[:email_subject].nil? ? options[:title] : options[:email_subject]
  9. email_message = options[:email_message].nil? ? "I thought you might be interested in this: #{url}" : "#{options[:email_message]} #{url}"
  10. email_action_url = options[:email_action_url].nil? ? '/rad_social/mail' : options[:email_action_url]
  11. render partial: 'widget/horizontal_widget',
  12. locals: { url: url,
  13. message: message,
  14. email_subject: email_subject,
  15. email_message: email_message,
  16. email_action_url: email_action_url }
  17. end
  18. end

app/helpers/scoped_helper.rb

0.0% lines covered

16 relevant lines. 0 lines covered and 16 lines missed.
    
  1. module ScopedHelper
  2. def self.included(base)
  3. base.module_eval do
  4. def title
  5. t = current_site.name
  6. t = TrustyCms::Config['admin.title'] || 'TrustyCMS' if t.blank?
  7. t
  8. end
  9. def subtitle
  10. st = current_site.subtitle
  11. st = TrustyCms::Config['admin.subtitle'] || 'publishing for small teams' if st.blank?
  12. st
  13. end
  14. end
  15. end
  16. end

app/helpers/site_helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module SiteHelper
  2. end

app/helpers/sites_helper.rb

0.0% lines covered

10 relevant lines. 0 lines covered and 10 lines missed.
    
  1. module SitesHelper
  2. def order_links(site)
  3. String.new.tap do |output|
  4. output << link_to(image('move_to_top.png', alt: 'Move to top'), move_to_top_admin_site_path(site), method: :put)
  5. output << link_to(image('move_higher.png', alt: 'Move up'), move_higher_admin_site_path(site), method: :post)
  6. output << link_to(image('move_lower.png', alt: 'Move down'), move_lower_admin_site_path(site), method: :post)
  7. output << link_to(image('move_to_bottom.png', alt: 'Move to bottom'), move_to_bottom_admin_site_path(site), method: :put)
  8. end
  9. end
  10. end

app/mailers/application_mailer.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. class ApplicationMailer < ActionMailer::Base
  2. end

app/mailers/devise_mailer.rb

0.0% lines covered

7 relevant lines. 0 lines covered and 7 lines missed.
    
  1. class DeviseMailer < Devise::Mailer
  2. def reset_password_instructions(record, token, opts = {})
  3. mail = super
  4. mail.subject = 'Reset Password for TrustyCMS'
  5. mail
  6. end
  7. end

app/mailers/rad_social_mailer.rb

0.0% lines covered

21 relevant lines. 0 lines covered and 21 lines missed.
    
  1. require 'roadie-rails'
  2. class RadSocialMailer < ApplicationMailer
  3. include Roadie::Rails::Automatic
  4. def social_mail(options)
  5. from_address = Mail::Address.new options[:from] # ex: "john@example.com"
  6. from_address.display_name = options[:from_name] # ex: "John Doe"
  7. @from_name = from_address.display_name
  8. @from_email = from_address
  9. @message = options[:message]
  10. @actual_from = ENV.fetch('RAD_SOCIAL_FROM_EMAIL')
  11. @actual_from = from_address if @actual_from.nil?
  12. mail({
  13. to: options[:to],
  14. from: @actual_from,
  15. reply_to: @from_email,
  16. subject: options[:subject],
  17. text: @message,
  18. content_type: 'text/html',
  19. })
  20. end
  21. end

app/models/admins_site.rb

0.0% lines covered

5 relevant lines. 0 lines covered and 5 lines missed.
    
  1. class AdminsSite < ActiveRecord::Base
  2. self.table_name = 'admins_sites'
  3. belongs_to :admin, class_name: 'User'
  4. belongs_to :site
  5. end

app/models/asset.rb

0.0% lines covered

195 relevant lines. 0 lines covered and 195 lines missed.
    
  1. class Asset < ActiveRecord::Base
  2. has_many :page_attachments, dependent: :destroy
  3. has_many :pages, through: :page_attachments
  4. has_site if respond_to? :has_site
  5. belongs_to :created_by, class_name: 'User'
  6. belongs_to :updated_by, class_name: 'User'
  7. default_scope { order('created_at DESC') }
  8. scope :latest, lambda { |limit|
  9. order('created_at DESC').limit(limit)
  10. }
  11. scope :of_types, lambda { |types|
  12. mimes = AssetType.slice(*types).map(&:mime_types).flatten
  13. Asset.select { |x| mimes.include?(x.asset_content_type) }
  14. }
  15. scope :matching, lambda { |term|
  16. where(['LOWER(assets.asset_file_name) LIKE (:term) OR LOWER(title) LIKE (:term) OR LOWER(caption) LIKE (:term)', { term: "%#{term.downcase}%" }])
  17. }
  18. scope :excepting, lambda { |assets|
  19. if assets.any?
  20. assets = assets.split(',') if assets.is_a?(String)
  21. asset_ids = assets.first.is_a?(Asset) ? assets.map(&:id) : assets
  22. where(["assets.id NOT IN(#{asset_ids.map { '?' }.join(',')})", *asset_ids])
  23. else
  24. {}
  25. end
  26. }
  27. has_one_attached :asset
  28. validates :asset,
  29. presence: true,
  30. blob:
  31. {
  32. content_type: %w[application/zip image/jpg image/jpeg image/png image/gif application/pdf text/css],
  33. size_range: 1..10.megabytes,
  34. }
  35. before_save :assign_title
  36. before_save :assign_uuid
  37. def asset_type
  38. AssetType.for(asset)
  39. end
  40. delegate :paperclip_processors, :paperclip_styles, :active_storage_styles, :style_dimensions, :style_format,
  41. to: :asset_type
  42. def thumbnail(style_name = 'original')
  43. return asset.url if style_name.to_s == 'original' || render_original(style_name)
  44. return asset_variant(style_name.to_s).processed.url if asset.variable?
  45. asset_type.icon(style_name.to_s)
  46. end
  47. def self.ransackable_attributes(auth_object = nil)
  48. %w[asset_content_type asset_file_name asset_file_size caption created_at created_by_id id original_extension original_height original_width title updated_at updated_by_id uuid]
  49. end
  50. def render_original(style_name)
  51. style_name.to_s == 'original' && asset.key.include?('culturaldistrict')
  52. end
  53. def asset_variant(style_name)
  54. case style_name
  55. when 'thumbnail'
  56. asset.variant(gravity: 'Center', resize: '100x100^', crop: '100x100+0+0')
  57. when 'small'
  58. asset.variant(gravity: 'Center', resize: '320x320^')
  59. when 'normal'
  60. asset.variant(gravity: 'Center', resize_to_limit: [asset.metadata[:width], asset.metadata[:height]])
  61. when 'icon'
  62. asset.variant(gravity: 'Center', resize: '50x50^')
  63. end
  64. end
  65. def style?(style_name = 'original')
  66. style_name == 'original' || paperclip_styles.keys.include?(style_name.to_sym)
  67. end
  68. def basename
  69. File.basename(asset_file_name, '.*') if asset_file_name
  70. end
  71. def extension(style_name = 'original')
  72. if style_name == 'original'
  73. original_extension
  74. elsif style = paperclip_styles[style_name.to_sym]
  75. style.format
  76. else
  77. original_extension
  78. end
  79. end
  80. def original_extension
  81. return asset_file_name.split('.').last.downcase if asset_file_name
  82. end
  83. def attached_to?(page)
  84. pages.include?(page)
  85. end
  86. def original_geometry
  87. @original_geometry ||= Paperclip::Geometry.new(original_width, original_height)
  88. end
  89. def geometry(style_name = 'original')
  90. unless style?(style_name)
  91. raise Paperclip::StyleError,
  92. "Requested style #{style_name} is not defined for this asset."
  93. end
  94. @geometry ||= {}
  95. begin
  96. @geometry[style_name] ||= if style_name.to_s == 'original'
  97. original_geometry
  98. else
  99. style = asset.styles[style_name.to_sym]
  100. original_geometry.transformed_by(style.geometry)
  101. # this can return dimensions for fully specified style sizes but not for relative sizes when there are no original dimensions
  102. end
  103. rescue Paperclip::TransformationError => e
  104. Rails.logger.warn "geometry transformation error: #{e}"
  105. original_geometry # returns a blank geometry if the real geometry cannot be calculated
  106. end
  107. end
  108. def aspect(style_name = 'original')
  109. geometry(style_name).aspect
  110. end
  111. def orientation(style_name = 'original')
  112. a = aspect(style_name)
  113. if a == nil?
  114. 'unknown'
  115. elsif a < 1.0
  116. 'vertical'
  117. elsif a > 1.0
  118. 'horizontal'
  119. else
  120. 'square'
  121. end
  122. end
  123. def width(style_name = 'original')
  124. geometry(style_name).width.to_i
  125. end
  126. def height(style_name = 'original')
  127. geometry(style_name).height.to_i
  128. end
  129. def square?(style_name = 'original')
  130. geometry(style_name).square?
  131. end
  132. def vertical?(style_name = 'original')
  133. geometry(style_name).vertical?
  134. end
  135. def horizontal?(style_name = 'original')
  136. geometry(style_name).horizontal?
  137. end
  138. def dimensions_known?
  139. original_width? && original_height?
  140. end
  141. private
  142. # at this point the file queue will not have been written
  143. # but the upload should be in place. We read dimensions from the
  144. # original file and calculate thumbnail dimensions later, on demand.
  145. def read_dimensions
  146. if image? && file = asset.queued_for_write[:original]
  147. geometry = Paperclip::Geometry.from_file(file)
  148. self.original_width = geometry.width
  149. self.original_height = geometry.height
  150. self.original_extension = File.extname(file.path)
  151. end
  152. true
  153. end
  154. def assign_title
  155. self.title = asset.filename.base
  156. end
  157. def assign_uuid
  158. self.uuid = SecureRandom.uuid unless uuid?
  159. end
  160. class << self
  161. def known_types
  162. AssetType.known_types
  163. end
  164. # searching and pagination moved to the controller
  165. def find_all_by_asset_types(asset_types, *args)
  166. with_asset_types(asset_types) { where *args }
  167. end
  168. def count_with_asset_types(asset_types, *args)
  169. with_asset_types(asset_types) { where(*args).count }
  170. end
  171. def with_asset_types(asset_types, &block)
  172. w_asset_types = AssetType.conditions_for(asset_types)
  173. with_scope(where(conditions: ["#{w_asset_types} = ?", block]))
  174. end
  175. end
  176. # called from AssetType to set type_condition? methods on Asset
  177. def self.define_class_method(name, &block)
  178. eigenclass.send :define_method, name, &block
  179. end
  180. # returns the return value of class << self block, which is self (as defined within that block)
  181. def self.eigenclass
  182. class << self
  183. self;
  184. end
  185. end
  186. # for backwards compatibility
  187. def self.thumbnail_sizes
  188. AssetType.find(:image).paperclip_styles
  189. end
  190. def self.thumbnail_names
  191. thumbnail_sizes.keys
  192. end
  193. # this is a convenience for image-pickers
  194. def self.thumbnail_options
  195. asset_sizes = thumbnail_sizes.map do |k, v|
  196. size_id = k
  197. size_description = "#{k}: "
  198. size_description << (v.is_a?(Array) ? v.join(' as ') : v)
  199. [size_description, size_id]
  200. end.sort_by { |pair| pair.last.to_s }
  201. asset_sizes.unshift ['Original (as uploaded)', 'original']
  202. asset_sizes
  203. end
  204. end

app/models/asset_type.rb

0.0% lines covered

172 relevant lines. 0 lines covered and 172 lines missed.
    
  1. class AssetType
  2. # The Asset Type encapsulates a type of attachment.
  3. # Conventionally this would a sensible category like 'image' or 'video'
  4. # that should be processed and presented in a particular way.
  5. # An AssetType currently provides:
  6. # * processor definitions for paperclip
  7. # * styles definitions for paperclip
  8. # * mime type list for file recognition
  9. # * selectors and scopes for retrieving this (or not this) category of asset
  10. # * radius tags for those subsets of assets (temporarily removed pending discussion of interface)
  11. @@types = []
  12. @@type_lookup = {}
  13. @@extension_lookup = {}
  14. @@mime_lookup = {}
  15. @@default_type = nil
  16. attr_reader :name, :processors, :styles, :icon_name, :catchall, :default_radius_tag
  17. def initialize(name, options = {})
  18. options = options.symbolize_keys
  19. @name = name
  20. @icon_name = options[:icon] || name
  21. @processors = options[:processors] || []
  22. @styles = options[:styles] || {}
  23. @styles = standard_styles if @styles == :standard
  24. @default_radius_tag = options[:default_radius_tag] || 'link'
  25. @extensions = options[:extensions] || []
  26. @extensions.each { |ext| @@extension_lookup[ext] ||= self }
  27. @mimes = options[:mime_types] || []
  28. @mimes.each { |mimetype| @@mime_lookup[mimetype] ||= self }
  29. this = self
  30. Asset.send :define_method, "#{name}?".intern do this.mime_types.include?(asset_content_type) end
  31. Asset.send :define_class_method, "#{name}_condition".intern do this.condition; end
  32. Asset.send :define_class_method, "not_#{name}_condition".intern do this.non_condition; end
  33. Asset.send :scope, plural.to_sym, -> { where(conditions: condition) }
  34. Asset.send :scope, "not_#{plural}".to_sym, -> { where(conditions: non_condition) }
  35. define_radius_tags
  36. @@types.push self
  37. @@type_lookup[@name] = self
  38. end
  39. def plural
  40. name.to_s.pluralize
  41. end
  42. def icon(style_name = 'icon')
  43. if File.exist?(Rails.root + "public/images/admin/assets/#{icon_name}_#{style_name}.png")
  44. "/assets/admin/#{icon_name}_#{style_name}.png"
  45. else
  46. "/assets/admin/#{icon_name}_icon.png"
  47. end
  48. end
  49. def icon_path(style_name = 'icon')
  50. Rails.root + "public#{icon(style_name)}"
  51. end
  52. def condition
  53. if @mimes.any?
  54. ["asset_content_type IN (#{@mimes.map { '?' }.join(',')})", *@mimes]
  55. else
  56. self.class.other_condition
  57. end
  58. end
  59. def sanitized_condition
  60. ActiveRecord::Base.send :sanitize_sql_array, condition
  61. end
  62. def non_condition
  63. if @mimes.any?
  64. ["NOT asset_content_type IN (#{@mimes.map { '?' }.join(',')})", *@mimes]
  65. else
  66. self.class.non_other_condition
  67. end
  68. end
  69. def sanitized_non_condition
  70. ActiveRecord::Base.send :sanitize_sql_array, non_condition
  71. end
  72. def mime_types
  73. @mimes
  74. end
  75. def paperclip_processors
  76. TrustyCms.config["assets.create_#{name}_thumbnails?"] ? processors : []
  77. end
  78. # Parses and combines the various ways in which paperclip styles can be defined, and normalises them into
  79. # the format that paperclip expects. Note that :styles => :standard has already been replaced with the
  80. # results of a call to standard_styles.
  81. # Styles are passed to paperclip as a hash and arbitrary keys can be passed through from configuration.
  82. #
  83. def paperclip_styles
  84. # Styles are not relevant if processors are not defined.
  85. @paperclip_styles ||= if paperclip_processors.any?
  86. normalize_style_rules(configured_styles.merge(styles))
  87. else
  88. {}
  89. end
  90. @paperclip_styles
  91. end
  92. def active_storage_styles
  93. @active_storage_styles ||= normalize_style_rules(configured_styles.merge(styles))
  94. end
  95. # Takes a motley collection of differently-defined styles and renders them into the standard hash-of-hashes format.
  96. # Solitary strings are assumed to be #
  97. def normalize_style_rules(styles = {})
  98. styles.each_pair do |name, rule|
  99. unless rule.is_a? Hash
  100. if rule =~ /\=/
  101. parameters = rule.split(',').collect { |parameter| parameter.split('=') } # array of pairs
  102. rule = Hash[parameters].symbolize_keys # into hash of :first => last
  103. else
  104. rule = { geometry: rule } # simplest case: name:geom|name:geom
  105. end
  106. end
  107. rule[:geometry] ||= rule.delete(:size)
  108. styles[name.to_sym] = rule
  109. end
  110. styles
  111. end
  112. def standard_styles
  113. {
  114. thumbnail: { geometry: '100x100#', format: :png },
  115. }
  116. end
  117. # Paperclip styles are defined in the config entry `assets.thumbnails.asset_type`, with the format:
  118. # foo:key-x,key=y,key=z|bar:key-x,key=y,key=z
  119. # where 'key' can be any parameter understood by your paperclip processors. Usually they include :geometry and :format.
  120. # A typical entry would be:
  121. #
  122. # standard:geometry=640x640>,format=jpg
  123. #
  124. # This method parses that string and returns the defined styles as a hash of style-defining strings that will later be normalized into hashes.
  125. #
  126. def configured_styles
  127. @configured_styles ||= if style_definitions = TrustyCms.config["assets.thumbnails.#{name}"]
  128. style_definitions.split('|').each_with_object({}) do |definition, styles|
  129. name, rule = definition.split(':')
  130. styles[name.strip.to_sym] = rule.to_s.strip
  131. end
  132. else
  133. {}
  134. end
  135. end
  136. def style_dimensions(style_name)
  137. if style = paperclip_styles[style_name.to_sym]
  138. style[:size]
  139. end
  140. end
  141. def define_radius_tags
  142. type = name
  143. Page.class_eval do
  144. tag "asset:if_#{type}" do |tag|
  145. tag.expand if find_asset(tag, tag.attr.dup).send("#{type}?".to_sym)
  146. end
  147. tag "asset:unless_#{type}" do |tag|
  148. tag.expand unless find_asset(tag, tag.attr.dup).send("#{type}?".to_sym)
  149. end
  150. end
  151. end
  152. # class methods
  153. def self.for(attachment)
  154. extension = attachment.record.original_extension
  155. from_extension(extension) || from_mimetype(attachment.content_type) || catchall
  156. end
  157. def self.from_extension(extension)
  158. @@extension_lookup[extension]
  159. end
  160. def self.from_mimetype(mimetype)
  161. @@mime_lookup[mimetype]
  162. end
  163. def self.catchall
  164. @@default_type ||= find(:other)
  165. end
  166. def self.known?(name)
  167. !find(name).nil?
  168. end
  169. def self.slice(*types)
  170. @@type_lookup.slice(*types.map(&:to_sym)).values if types # Hash#slice is provided by will_paginate
  171. end
  172. def self.find(type)
  173. @@type_lookup[type] if type
  174. end
  175. def self.[](type)
  176. find(type)
  177. end
  178. def self.all
  179. @@types
  180. end
  181. def self.known_types
  182. @@types.map(&:name) # to preserve order
  183. end
  184. def self.known_mimetypes
  185. @@mime_lookup.keys
  186. end
  187. def self.mime_types_for(*names)
  188. names.collect { |name| find(name).mime_types }.flatten
  189. end
  190. def self.conditions_for(*names)
  191. names.collect { |name| find(name).sanitized_condition }.join(' OR ')
  192. end
  193. def self.non_other_condition
  194. ["asset_content_type IN (#{known_mimetypes.map { '?' }.join(',')})", *known_mimetypes]
  195. end
  196. def self.other_condition
  197. ["NOT asset_content_type IN (#{known_mimetypes.map { '?' }.join(',')})", *known_mimetypes]
  198. end
  199. end

app/models/file_not_found_page.rb

0.0% lines covered

24 relevant lines. 0 lines covered and 24 lines missed.
    
  1. class FileNotFoundPage < Page
  2. def cache_timeout
  3. 5.minutes
  4. end
  5. def allowed_children
  6. []
  7. end
  8. description %{
  9. A "File Not Found" page can be used to override the default error
  10. page in the event that a page is not found among a page's children.
  11. To create a "File Not Found" error page for an entire Web site, create
  12. a page that is a child of the root page and assign it "File Not Found"
  13. page type.
  14. }
  15. tag 'attempted_url' do |_tag|
  16. CGI.escapeHTML(request.request_uri) unless request.nil?
  17. end
  18. def virtual?
  19. true
  20. end
  21. def response_code
  22. 404
  23. end
  24. end

app/models/haml_filter.rb

0.0% lines covered

5 relevant lines. 0 lines covered and 5 lines missed.
    
  1. class HamlFilter < TextFilter
  2. def filter(text)
  3. Haml::Engine.new(text).render.gsub(/&lt;(\/)?r:(.+?)\s*(\/?\\?)&gt;/m, '<\\1r:\\2\\3>')
  4. end
  5. end

app/models/layout.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. 1 class Layout < ActiveRecord::Base
  2. # Default Order
  3. 6 default_scope { order('name') }
  4. # Associations
  5. 1 has_many :pages
  6. 1 belongs_to :created_by, class_name: 'User'
  7. 1 belongs_to :updated_by, class_name: 'User'
  8. # Validations
  9. 1 validates_presence_of :name
  10. 1 validates_uniqueness_of :name
  11. 1 validates_length_of :name, maximum: 100
  12. end

app/models/menu_renderer.rb

0.0% lines covered

111 relevant lines. 0 lines covered and 111 lines missed.
    
  1. module MenuRenderer
  2. def exclude(*type_names)
  3. @excluded_class_names ||= []
  4. @excluded_class_names.concat(type_names).uniq!
  5. end
  6. module_function :exclude
  7. def excluded_class_names
  8. MenuRenderer.instance_variable_get(:@excluded_class_names)
  9. end
  10. module_function :excluded_class_names
  11. public :excluded_class_names
  12. def view=(val)
  13. @view = val
  14. end
  15. def view
  16. @view
  17. end
  18. def additional_menu_features?
  19. @additional_menu_features ||= (menu_renderer_module_name != 'MenuRenderer' && Object.const_defined?(menu_renderer_module_name))
  20. end
  21. def menu_renderer_module_name
  22. simple_name = class_name.to_s.sub('Page', '')
  23. "#{simple_name}MenuRenderer"
  24. end
  25. def menu_renderer_modules
  26. [Object.const_get(menu_renderer_module_name)]
  27. end
  28. def allowed_child_classes
  29. (allowed_children_cache.to_s.split(',') - Array(excluded_class_names)).map do |name|
  30. begin
  31. name.constantize
  32. rescue LoadError, NameError => _e
  33. nil
  34. end
  35. end.compact
  36. end
  37. def default_child_item
  38. menu_item(default_child)
  39. end
  40. def separator_item
  41. view.content_tag :li, '', class: 'separator'
  42. end
  43. def child_items
  44. (allowed_child_classes - [self.class.default_child]).map do |child|
  45. menu_item(child)
  46. end
  47. end
  48. def menu_items
  49. [default_child_item, separator_item] + child_items
  50. end
  51. def menu_list
  52. view.content_tag :ul, menu_items.join.html_safe, class: 'menu', id: "allowed_children_#{id}"
  53. end
  54. def remove_link
  55. view.link_to('<i class="fas fa-minus-circle"></i> '.html_safe + I18n.t('remove'), view.remove_admin_page_url(self), class: 'action')
  56. end
  57. def remove_option
  58. remove_link
  59. end
  60. def add_child_disabled?
  61. allowed_child_classes.size == 0
  62. end
  63. def disabled_add_child_link
  64. view.content_tag :span, view.image('plus_disabled') + ' Add Child', class: 'action disabled'
  65. end
  66. def add_child_link
  67. view.link_to('<i class="fas fa-plus-circle"></i> Add Child'.html_safe, view.new_admin_page_child_path(self, page_class: default_child.name), class: 'action')
  68. end
  69. def add_child_link_with_menu_hook
  70. view.link_to('<i class="fas fa-plus-circle"></i> Add Child'.html_safe, "#allowed_children_#{id}", class: 'action dropdown')
  71. end
  72. def add_child_menu
  73. menu_list
  74. end
  75. def add_child_link_with_menu
  76. add_child_link_with_menu_hook + add_child_menu
  77. end
  78. def add_child_option
  79. if add_child_disabled?
  80. disabled_add_child_link
  81. else
  82. if allowed_child_classes.size == 1
  83. add_child_link
  84. else
  85. add_child_link_with_menu
  86. end
  87. end
  88. end
  89. private
  90. def clean_page_description(page_class)
  91. page_class.description.to_s.strip.gsub(/\t/, '').gsub(/\s+/, ' ')
  92. end
  93. def menu_item(child_class)
  94. view.content_tag(:li, menu_link(child_class))
  95. end
  96. def menu_link(child_class)
  97. title = clean_page_description(child_class)
  98. path = view.new_admin_page_child_path(self, page_class: child_class.name)
  99. text = link_text_for_child_class(child_class.name)
  100. view.link_to(text, path, title: title)
  101. end
  102. def link_text_for_child_class(given_class_name)
  103. translation_key = if given_class_name == 'Page' || given_class_name.blank?
  104. 'normal_page'
  105. else
  106. given_class_name.sub('Page', '').underscore
  107. end
  108. fallback = given_class_name == 'Page' ? 'Page' : given_class_name.sub('Page', '').titleize
  109. I18n.t(translation_key, default: fallback)
  110. end
  111. end

app/models/page.rb

0.0% lines covered

319 relevant lines. 0 lines covered and 319 lines missed.
    
  1. require 'trusty_cms/taggable'
  2. class Page < ActiveRecord::Base
  3. has_paper_trail
  4. class MissingRootPageError < StandardError
  5. def initialize(message = 'Database missing root page')
  6. ; super
  7. end
  8. end
  9. # Callbacks
  10. before_save :update_virtual, :update_published_datetime, :set_allowed_children_cache
  11. # Associations
  12. acts_as_tree order: 'position ASC'
  13. has_many :parts, -> { order(:id) }, class_name: 'PagePart', foreign_key: :page_id, autosave: true, dependent: :destroy
  14. accepts_nested_attributes_for :parts, allow_destroy: true
  15. has_many :fields, -> { order(:id) }, class_name: 'PageField', foreign_key: :page_id, autosave: true, dependent: :destroy
  16. accepts_nested_attributes_for :fields, allow_destroy: true
  17. belongs_to :layout
  18. belongs_to :created_by, class_name: 'User'
  19. belongs_to :updated_by, class_name: 'User'
  20. # Validations
  21. validates_presence_of :title, :slug, :breadcrumb, :status_id
  22. validates_length_of :title, maximum: 255
  23. validates_length_of :slug, maximum: 100
  24. validates_length_of :breadcrumb, maximum: 160
  25. validates_format_of :slug, with: %r{\A([-_.A-Za-z0-9]*|/)\z}
  26. validates_uniqueness_of :slug, scope: :parent_id
  27. validate :valid_class_name
  28. include TrustyCms::Taggable
  29. include StandardTags
  30. include Annotatable
  31. annotate :description
  32. attr_accessor :request, :response, :pagination_parameters
  33. class_attribute :default_child
  34. self.default_child = self
  35. self.inheritance_column = 'class_name'
  36. def layout_with_inheritance
  37. if layout_without_inheritance
  38. layout_without_inheritance
  39. else
  40. parent.layout if parent?
  41. end
  42. end
  43. alias_method :layout_without_inheritance, :layout
  44. alias_method :layout, :layout_with_inheritance
  45. def description
  46. self['description']
  47. end
  48. def description=(value)
  49. self['description'] = value
  50. end
  51. def cache?
  52. true
  53. end
  54. def child_path(child)
  55. clean_path(path + '/' + child.slug)
  56. end
  57. alias_method :child_url, :child_path
  58. def part(name)
  59. if new_record? || parts.to_a.any?(&:new_record?)
  60. parts.to_a.find { |p| p.name == name.to_s }
  61. else
  62. parts.find_by_name name.to_s
  63. end
  64. end
  65. def part?(name)
  66. !part(name).nil?
  67. end
  68. def has_or_inherits_part?(name)
  69. part?(name) || inherits_part?(name)
  70. end
  71. def inherits_part?(name)
  72. !part?(name) && ancestors.any? { |page| page.part?(name) }
  73. end
  74. def field(name)
  75. if new_record? || fields.any?(&:new_record?)
  76. fields.detect { |f| f.name.downcase == name.to_s.downcase }
  77. else
  78. fields.find_by_name name.to_s
  79. end
  80. end
  81. def published?
  82. status == Status[:published]
  83. end
  84. def scheduled?
  85. status == Status[:scheduled]
  86. end
  87. def status
  88. Status.find(status_id)
  89. end
  90. def status=(value)
  91. self.status_id = value.id
  92. end
  93. def path
  94. if parent?
  95. parent.child_path(self)
  96. else
  97. clean_path(slug)
  98. end
  99. end
  100. alias_method :url, :path
  101. def process(request, response)
  102. @request = request
  103. @response = response
  104. set_response_headers(@response)
  105. @response.body = render
  106. @response.status = response_code
  107. end
  108. def headers
  109. # Return a blank hash that child classes can override or merge
  110. {}
  111. end
  112. def set_response_headers(response)
  113. set_content_type(response)
  114. headers.each { |k, v| response.headers[k] = v }
  115. end
  116. def self.save_order(new_position)
  117. dictionary = Hash[*new_position.flatten(1)]
  118. dictionary.each do |id, position|
  119. page = Page.find_by_id(id)
  120. page.position = position if page.position.present?
  121. page.save
  122. end
  123. end
  124. def self.ransackable_attributes(auth_object = nil)
  125. ['site_id', 'title']
  126. end
  127. private :set_response_headers
  128. def set_content_type(response)
  129. if layout
  130. content_type = layout.content_type.to_s.strip
  131. if content_type.present?
  132. response.headers['Content-Type'] = content_type
  133. end
  134. end
  135. end
  136. private :set_content_type
  137. def response_code
  138. 200
  139. end
  140. def render
  141. if layout
  142. parse_object(layout)
  143. else
  144. render_part(:body)
  145. end
  146. end
  147. def render_part(part_name)
  148. part = part(part_name)
  149. if part
  150. parse_object(part)
  151. else
  152. ''
  153. end
  154. end
  155. def render_snippet(snippet)
  156. parse_object(snippet)
  157. end
  158. def find_by_path(path, live = true, clean = true)
  159. return nil if virtual?
  160. path = clean_path(path) if clean
  161. my_path = self.path
  162. if (my_path == path) && ((not live) || published?)
  163. return self
  164. elsif path =~ /^#{Regexp.quote(my_path)}([^\/]*)/
  165. slug_child = children.find_by_slug($1)
  166. if slug_child
  167. found = slug_child.find_by_path(path, live, clean)
  168. return found if found
  169. end
  170. children.each do |child|
  171. found = child.find_by_path(path, live, clean)
  172. return found if found
  173. end
  174. end
  175. unless slug_child
  176. file_not_found_types = ([FileNotFoundPage] + FileNotFoundPage.descendants)
  177. file_not_found_names = file_not_found_types.collect { |x| x.name }
  178. condition = (['class_name = ?'] * file_not_found_names.length).join(' or ')
  179. condition = "status_id = #{Status[:published].id} and (#{condition})" if live
  180. return children.where([condition] + file_not_found_names).first
  181. end
  182. slug_child
  183. end
  184. def update_published_datetime
  185. self.published_at = Time.zone.now if published? && published_at.blank?
  186. end
  187. def default_child
  188. self.class.default_child
  189. end
  190. def allowed_children_lookup
  191. [default_child, *Page.descendants.sort_by(&:name)].uniq
  192. end
  193. def set_allowed_children_cache
  194. self.allowed_children_cache = allowed_children_lookup.collect(&:name).join(',')
  195. end
  196. class << self
  197. def root
  198. find_by_parent_id(nil)
  199. end
  200. def find_by_path(path, live = true)
  201. raise MissingRootPageError unless root
  202. root.find_by_path(path, live)
  203. end
  204. def date_column_names
  205. columns.collect { |c| c.name if c.sql_type =~ /(date|time)/ }.compact
  206. end
  207. def display_name(string = nil)
  208. if string
  209. @display_name = string
  210. else
  211. @display_name ||= begin
  212. n = name.to_s
  213. n.sub(/^(.+?)Page$/, '\1')
  214. n.gsub(/([A-Z])/, ' \1')
  215. n.strip
  216. end
  217. end
  218. @display_name = @display_name + ' - not installed' if missing? && @display_name !~ /not installed/
  219. @display_name
  220. end
  221. def display_name=(string)
  222. display_name(string)
  223. end
  224. def load_subclasses
  225. ([TRUSTY_CMS_ROOT] + TrustyCms::Extension.descendants.map(&:root)).each do |path|
  226. Dir["#{path}/app/models/*_page.rb"].each do |page|
  227. $1.camelize.constantize if page =~ %r{/([^/]+)\.rb}
  228. end
  229. end
  230. if database_exists?
  231. if ActiveRecord::Base.connection.data_sources.include?('pages') && Page.column_names.include?('class_name') # Assume that we have bootstrapped
  232. Page.connection.select_values("SELECT DISTINCT class_name FROM pages WHERE class_name <> '' AND class_name IS NOT NULL").each do |p|
  233. begin
  234. p.constantize
  235. rescue NameError, LoadError
  236. # Rubocop: The use of eval is a serious security risk.
  237. # eval(%Q{class #{p} < Page; acts_as_tree; def self.missing?; true end end}, TOPLEVEL_BINDING)
  238. Rails.logger.error NameError
  239. end
  240. end
  241. end
  242. end
  243. end
  244. def new_with_defaults(config = TrustyCms::Config)
  245. page = new
  246. page.parts.concat default_page_parts(config)
  247. page.fields.concat default_page_fields(config)
  248. default_status = config['defaults.page.status']
  249. page.status = Status[default_status] if default_status
  250. page
  251. end
  252. def is_descendant_class_name?(class_name)
  253. (Page.descendants.map(&:to_s) + [nil, '', 'Page']).include?(class_name)
  254. end
  255. def descendant_class(class_name)
  256. raise ArgumentError.new('argument must be a valid descendant of Page') unless is_descendant_class_name?(class_name)
  257. if ['', nil, 'Page'].include?(class_name)
  258. Page
  259. else
  260. class_name.constantize
  261. end
  262. end
  263. def missing?
  264. false
  265. end
  266. private
  267. def default_page_parts(config = TrustyCms::Config)
  268. default_parts = config['defaults.page.parts'].to_s.strip.split(/\s*,\s*/)
  269. default_parts.map do |name|
  270. PagePart.new(name: name, filter_id: config['defaults.page.filter'])
  271. end
  272. end
  273. def default_page_fields(config = TrustyCms::Config)
  274. default_fields = config['defaults.page.fields'].to_s.strip.split(/\s*,\s*/)
  275. default_fields.map do |name|
  276. PageField.new(name: name)
  277. end
  278. end
  279. end
  280. private
  281. def valid_class_name
  282. unless Page.is_descendant_class_name?(class_name)
  283. errors.add :class_name, 'must be set to a valid descendant of Page'
  284. end
  285. end
  286. def update_virtual
  287. self.virtual = if self.class == Page.descendant_class(class_name)
  288. virtual?
  289. else
  290. Page.descendant_class(class_name).new.virtual?
  291. end
  292. true
  293. end
  294. def clean_path(path)
  295. "/#{path.to_s.strip}".gsub(%r{//+}, '/')
  296. end
  297. alias_method :clean_url, :clean_path
  298. def parent?
  299. !parent.nil?
  300. end
  301. def database_exists?
  302. ActiveRecord::Base.connection
  303. rescue ActiveRecord::NoDatabaseError
  304. false
  305. else
  306. true
  307. end
  308. def lazy_initialize_parser_and_context
  309. unless @parser && @context
  310. @context = PageContext.new(self)
  311. @parser = Radius::Parser.new(@context, tag_prefix: 'r')
  312. end
  313. @parser
  314. end
  315. def parse(text)
  316. text = '' if text.nil?
  317. lazy_initialize_parser_and_context.parse(text)
  318. end
  319. def parse_object(object)
  320. text = object.content || ''
  321. text = parse(text)
  322. text = object.filter.filter(text) if object.respond_to? :filter_id
  323. text
  324. end
  325. end

app/models/page_attachment.rb

0.0% lines covered

13 relevant lines. 0 lines covered and 13 lines missed.
    
  1. class PageAttachment < ActiveRecord::Base
  2. belongs_to :asset
  3. belongs_to :page
  4. attr_accessor :selected
  5. accepts_nested_attributes_for :asset
  6. acts_as_list scope: :page_id
  7. def selected?
  8. !!selected
  9. end
  10. # a small change to the method in acts_as_list so that we don't override
  11. # the position value if it has already been set (as it usually is for new attachments)
  12. def add_to_list_bottom
  13. self[position_column] ||= bottom_position_in_list.to_i + 1
  14. end
  15. end

app/models/page_context.rb

0.0% lines covered

38 relevant lines. 0 lines covered and 38 lines missed.
    
  1. class PageContext < Radius::Context
  2. attr_reader :page
  3. def initialize(page)
  4. super
  5. @page = page
  6. globals.page = @page
  7. page.tags.each do |name|
  8. define_tag(name) { |tag_binding| page.render_tag(name, tag_binding) }
  9. end
  10. end
  11. def dup
  12. rv = self.class.new(page)
  13. rv.globals = globals.dup
  14. rv.definitions = definitions.dup
  15. rv
  16. end
  17. def render_tag(name, attributes = {}, &block)
  18. binding = @tag_binding_stack.last
  19. locals = binding ? binding.locals : globals
  20. set_process_variables(locals.page)
  21. super
  22. rescue Exception => e
  23. raise e if raise_errors?
  24. @tag_binding_stack.pop unless @tag_binding_stack.last == binding
  25. render_error_message(e.message)
  26. end
  27. private
  28. def render_error_message(message)
  29. "<div><strong>#{message}</strong></div>"
  30. end
  31. def set_process_variables(page)
  32. page.request ||= @page.request
  33. page.response ||= @page.response
  34. end
  35. def raise_errors?
  36. Rails.env != 'production'
  37. end
  38. end

app/models/page_field.rb

0.0% lines covered

4 relevant lines. 0 lines covered and 4 lines missed.
    
  1. class PageField < ActiveRecord::Base
  2. has_paper_trail
  3. validates_presence_of :name
  4. end

app/models/page_part.rb

0.0% lines covered

12 relevant lines. 0 lines covered and 12 lines missed.
    
  1. class PagePart < ActiveRecord::Base
  2. has_paper_trail
  3. # Default Order
  4. default_scope { order('name') }
  5. # Associations
  6. belongs_to :page
  7. # Validations
  8. validates_presence_of :name
  9. validates_length_of :name, maximum: 100
  10. validates_length_of :filter_id, maximum: 25, allow_nil: true
  11. object_id_attr :filter, TextFilter
  12. def after_initialize
  13. self.filter_id ||= TrustyCms::Config['defaults.page.filter'] if new_record?
  14. end
  15. end

app/models/rails_page.rb

0.0% lines covered

24 relevant lines. 0 lines covered and 24 lines missed.
    
  1. class RailsPage < Page
  2. display_name 'Application'
  3. attr_accessor :breadcrumbs
  4. def find_by_path(url, live = true, clean = true)
  5. found_page = super
  6. if found_page.nil? || found_page.is_a?(FileNotFoundPage)
  7. url = clean_url(url) if clean
  8. self if url.starts_with?(self.url)
  9. else
  10. found_page
  11. end
  12. end
  13. def url=(path)
  14. @url = path
  15. end
  16. def url
  17. @url || super
  18. end
  19. def build_parts_from_hash!(content)
  20. content.each do |k, v|
  21. (part(k) || parts.build(name: k.to_s, filter_id: '')).content = v
  22. end
  23. end
  24. end

app/models/site.rb

0.0% lines covered

62 relevant lines. 0 lines covered and 62 lines missed.
    
  1. # The site class includes - in find_for_host - some key retrieval and creation logic that is called from ApplicationController to set the current site context.
  2. # Otherwise it's just another Trusty data model.
  3. require 'acts_as_list'
  4. class Site < ActiveRecord::Base
  5. acts_as_list
  6. belongs_to :created_by, class_name: 'User'
  7. belongs_to :updated_by, class_name: 'User'
  8. belongs_to :production_homepage, class_name: 'ProductionPage'
  9. has_many :admins_sites
  10. has_many :admins, through: :admins_sites, class_name: 'User'
  11. default_scope { order('position ASC') }
  12. class << self
  13. attr_accessor :several
  14. # I've added one or two sql queries here for the sake of a separate default method
  15. def find_for_host(hostname = '')
  16. return default if hostname.blank?
  17. sites = includes(:homepage).where('domain IS NOT NULL')
  18. site = sites.find { |site| hostname == site.base_domain || hostname =~ Regexp.compile(site.domain) }
  19. site || default
  20. end
  21. # Site.default returns the the first site it can find with an empty domain pattern.
  22. def default
  23. find_by_domain('') || find_by_domain(nil) || catchall
  24. end
  25. # If none is found, we are probably brand new, so a workable default site is created.
  26. def catchall
  27. create({
  28. domain: '',
  29. name: 'default_site',
  30. base_domain: 'localhost',
  31. homepage: Page.find_by_parent_id(nil),
  32. })
  33. end
  34. # Returns true if more than one site is present. This is normally only used to make interface decisions, eg whether to show the site-chooser dropdown.
  35. def several?
  36. several = (count > 1) if several.nil?
  37. end
  38. end
  39. belongs_to :homepage, class_name: 'Page', foreign_key: 'homepage_id'
  40. validates_presence_of :name, :base_domain
  41. validates_uniqueness_of :domain
  42. after_create :create_homepage
  43. after_save :reload_routes
  44. # Returns the fully specified web address for the supplied path, or the root of this site if no path is given.
  45. def url(path = '/')
  46. uri = URI.join("http://#{base_domain}", path)
  47. uri.to_s
  48. end
  49. # Returns the fully specified web address for the development version of this site and the supplied path, or the root of this site if no path is given.
  50. def dev_url(path = '/')
  51. uri = URI.join("http://#{TrustyCms::Config['dev.host'] || 'dev'}.#{base_domain}", path)
  52. uri.to_s
  53. end
  54. def create_homepage
  55. if homepage_id.blank?
  56. self.homepage = build_homepage(title: "#{name} Homepage",
  57. slug: name.to_slug.to_s, breadcrumb: 'Home')
  58. default_status = TrustyCms::Config['defaults.page.status']
  59. homepage.status = Status[default_status] if default_status
  60. default_parts = TrustyCms::Config['defaults.page.parts'].to_s.strip.split(/\s*,\s*/)
  61. default_parts.each do |name|
  62. homepage.parts << PagePart.new(name: name, filter_id: TrustyCms::Config['defaults.page.filter'])
  63. end
  64. save
  65. end
  66. end
  67. def reload_routes
  68. TrustyCms::Application.reload_routes!
  69. end
  70. end

app/models/snippet.rb

91.67% lines covered

12 relevant lines. 11 lines covered and 1 lines missed.
    
  1. 1 class Snippet < ActiveRecord::Base
  2. # Default Order
  3. 6 default_scope { order('name') }
  4. # Associations
  5. 1 belongs_to :created_by, class_name: 'User'
  6. 1 belongs_to :updated_by, class_name: 'User'
  7. # Validations
  8. 1 validates_presence_of :name
  9. 1 validates_length_of :name, maximum: 100
  10. 1 validates_length_of :filter_id, maximum: 25, allow_nil: true
  11. 1 validates_format_of :name, with: %r{\A\S*\z}
  12. 1 validates_uniqueness_of :name
  13. 1 object_id_attr :filter, TextFilter
  14. 1 def after_initialize
  15. self.filter_id ||= TrustyCms::Config['defaults.snippet.filter'] if new_record?
  16. end
  17. end

app/models/snippet_finder.rb

0.0% lines covered

20 relevant lines. 0 lines covered and 20 lines missed.
    
  1. class SnippetFinder
  2. class << self
  3. def find(id)
  4. find_map('find', id)
  5. end
  6. def find_by_name(name)
  7. find_map('find_by_name', name)
  8. end
  9. def finder_types
  10. [Snippet]
  11. end
  12. private
  13. def find_map(meth, *args)
  14. finder_types.find do |type|
  15. found = type.send(meth, *args)
  16. return found if found
  17. end
  18. end
  19. end
  20. end

app/models/snippet_tags.rb

0.0% lines covered

61 relevant lines. 0 lines covered and 61 lines missed.
    
  1. module SnippetTags
  2. include TrustyCms::Taggable
  3. class TagError < StandardError; end
  4. desc %{
  5. Renders the snippet specified in the @name@ attribute within the context of a page.
  6. *Usage:*
  7. <pre><code><r:snippet name="snippet_name" /></code></pre>
  8. When used as a double tag, the part in between both tags may be used within the
  9. snippet itself, being substituted in place of @<r:yield/>@.
  10. *Usage:*
  11. <pre><code><r:snippet name="snippet_name">Lorem ipsum dolor...</r:snippet></code></pre>
  12. }
  13. tag 'snippet' do |tag|
  14. required_attr(tag, 'name')
  15. name = tag['name']
  16. snippet = snippet_cache(name.strip)
  17. if snippet
  18. tag.locals.yield = tag.expand if tag.double?
  19. tag.globals.page.render_snippet(snippet)
  20. else
  21. raise TagError.new("snippet '#{name}' not found")
  22. end
  23. end
  24. def snippet_cache(name)
  25. @snippet_cache ||= {}
  26. snippet = @snippet_cache[name]
  27. unless snippet
  28. snippet = SnippetFinder.find_by_name(name)
  29. @snippet_cache[name] = snippet
  30. end
  31. snippet
  32. end
  33. private :snippet_cache
  34. desc %{
  35. Used within a snippet as a placeholder for substitution of child content, when
  36. the snippet is called as a double tag.
  37. *Usage (within a snippet):*
  38. <pre><code>
  39. <div id="outer">
  40. <p>before</p>
  41. <r:yield/>
  42. <p>after</p>
  43. </div>
  44. </code></pre>
  45. If the above snippet was named "yielding", you could call it from any Page,
  46. Layout or Snippet as follows:
  47. <pre><code><r:snippet name="yielding">Content within</r:snippet></code></pre>
  48. Which would output the following:
  49. <pre><code>
  50. <div id="outer">
  51. <p>before</p>
  52. Content within
  53. <p>after</p>
  54. </div>
  55. </code></pre>
  56. When called in the context of a Page or a Layout, @<r:yield/>@ outputs nothing.
  57. }
  58. tag 'yield' do |tag|
  59. tag.locals.yield
  60. end
  61. end

app/models/standard_tags.rb

0.0% lines covered

936 relevant lines. 0 lines covered and 936 lines missed.
    
  1. require 'trusty_cms/taggable'
  2. module StandardTags
  3. include TrustyCms::Taggable
  4. require 'will_paginate/view_helpers'
  5. include WillPaginate::ViewHelpers
  6. class TagError < StandardError; end
  7. desc %{
  8. Causes the tags referring to a page's attributes to refer to the current page.
  9. *Usage:*
  10. <pre><code><r:page>...</r:page></code></pre>
  11. }
  12. tag 'page' do |tag|
  13. tag.locals.page = tag.globals.page
  14. tag.expand
  15. end
  16. %i[breadcrumb slug title].each do |method|
  17. desc %{
  18. Renders the @#{method}@ attribute of the current page.
  19. }
  20. tag method.to_s do |tag|
  21. tag.locals.page.send(method)
  22. end
  23. end
  24. desc %{
  25. Renders the @path@ attribute of the current page.
  26. }
  27. tag 'path' do |tag|
  28. relative_url_for(tag.locals.page.path, tag.globals.page.request)
  29. end
  30. desc %{
  31. Gives access to a page's children.
  32. *Usage:*
  33. <pre><code><r:children>...</r:children></code></pre>
  34. }
  35. tag 'children' do |tag|
  36. tag.locals.children = tag.locals.page.children
  37. tag.expand
  38. end
  39. desc %{
  40. Renders the total number of children.
  41. }
  42. tag 'children:count' do |tag|
  43. options = children_find_options(tag)
  44. options.delete(:order) # Order is irrelevant
  45. tag.locals.children.count(options)
  46. end
  47. desc %{
  48. Returns the first child. Inside this tag all page attribute tags are mapped to
  49. the first child. Takes the same ordering options as @<r:children:each>@.
  50. *Usage:*
  51. <pre><code><r:children:first>...</r:children:first></code></pre>
  52. }
  53. tag 'children:first' do |tag|
  54. options = children_find_options(tag)
  55. children = tag.locals.children.where(options)
  56. if first = children.first
  57. tag.locals.page = first
  58. tag.expand
  59. end
  60. end
  61. desc %{
  62. Returns the last child. Inside this tag all page attribute tags are mapped to
  63. the last child. Takes the same ordering options as @<r:children:each>@.
  64. *Usage:*
  65. <pre><code><r:children:last>...</r:children:last></code></pre>
  66. }
  67. tag 'children:last' do |tag|
  68. options = children_find_options(tag)
  69. children = tag.locals.children.where(options)
  70. if last = children.last
  71. tag.locals.page = last
  72. tag.expand
  73. end
  74. end
  75. desc %{
  76. Cycles through each of the children. Inside this tag all page attribute tags
  77. are mapped to the current child page.
  78. Supply @paginated="true"@ to paginate the displayed list. will_paginate view helper
  79. options can also be specified, including @per_page@, @previous_label@, @next_label@,
  80. @class@, @separator@, @inner_window@ and @outer_window@.
  81. *Usage:*
  82. <pre><code><r:children:each [offset="number"] [limit="number"]
  83. [by="published_at|updated_at|created_at|slug|title|keywords|description"]
  84. [order="asc|desc"]
  85. [status="draft|reviewed|published|hidden|all"]
  86. [paginated="true"]
  87. [per_page="number"]
  88. >
  89. ...
  90. </r:children:each>
  91. </code></pre>
  92. }
  93. tag 'children:each' do |tag|
  94. render_children_with_pagination(tag)
  95. end
  96. desc %{
  97. The pagination tag is not usually called directly. Supply paginated="true" when you display a list and it will
  98. be automatically display only the current page of results, with pagination controls at the bottom.
  99. *Usage:*
  100. <pre><code><r:children:each paginated="true" per_page="50" container="false" previous_label="foo" next_label="bar">
  101. <r:child>...</r:child>
  102. </r:children:each>
  103. </code></pre>
  104. }
  105. tag 'pagination' do |tag|
  106. if tag.locals.paginated_list
  107. will_paginate(tag.locals.paginated_list, will_paginate_options(tag))
  108. end
  109. end
  110. desc %{
  111. Page attribute tags inside of this tag refer to the current child. This is occasionally
  112. useful if you are inside of another tag (like &lt;r:find&gt;) and need to refer back to the
  113. current child.
  114. *Usage:*
  115. <pre><code><r:children:each>
  116. <r:child>...</r:child>
  117. </r:children:each>
  118. </code></pre>
  119. }
  120. tag 'children:each:child' do |tag|
  121. tag.locals.page = tag.locals.child
  122. tag.expand
  123. end
  124. desc %{
  125. Renders the tag contents only if the current page is the first child in the context of
  126. a children:each tag
  127. *Usage:*
  128. <pre><code><r:children:each>
  129. <r:if_first >
  130. ...
  131. </r:if_first>
  132. </r:children:each>
  133. </code></pre>
  134. }
  135. tag 'children:each:if_first' do |tag|
  136. tag.expand if tag.locals.first_child
  137. end
  138. desc %{
  139. Renders the tag contents unless the current page is the first child in the context of
  140. a children:each tag
  141. *Usage:*
  142. <pre><code><r:children:each>
  143. <r:unless_first >
  144. ...
  145. </r:unless_first>
  146. </r:children:each>
  147. </code></pre>
  148. }
  149. tag 'children:each:unless_first' do |tag|
  150. tag.expand unless tag.locals.first_child
  151. end
  152. desc %{
  153. Renders the tag contents only if the current page is the last child in the context of
  154. a children:each tag
  155. *Usage:*
  156. <pre><code><r:children:each>
  157. <r:if_last >
  158. ...
  159. </r:if_last>
  160. </r:children:each>
  161. </code></pre>
  162. }
  163. tag 'children:each:if_last' do |tag|
  164. tag.expand if tag.locals.last_child
  165. end
  166. desc %{
  167. Renders the tag contents unless the current page is the last child in the context of
  168. a children:each tag
  169. *Usage:*
  170. <pre><code><r:children:each>
  171. <r:unless_last >
  172. ...
  173. </r:unless_last>
  174. </r:children:each>
  175. </code></pre>
  176. }
  177. tag 'children:each:unless_last' do |tag|
  178. tag.expand unless tag.locals.last_child
  179. end
  180. desc %{
  181. Renders the tag contents only if the contents do not match the previous header. This
  182. is extremely useful for rendering date headers for a list of child pages.
  183. If you would like to use several header blocks you may use the @name@ attribute to
  184. name the header. When a header is named it will not restart until another header of
  185. the same name is different.
  186. Using the @restart@ attribute you can cause other named headers to restart when the
  187. present header changes. Simply specify the names of the other headers in a semicolon
  188. separated list.
  189. *Usage:*
  190. <pre><code><r:children:each>
  191. <r:header [name="header_name"] [restart="name1[;name2;...]"]>
  192. ...
  193. </r:header>
  194. </r:children:each>
  195. </code></pre>
  196. }
  197. tag 'children:each:header' do |tag|
  198. previous_headers = tag.locals.previous_headers
  199. name = tag.attr['name'] || :unnamed
  200. restart = (tag.attr['restart'] || '').split(';')
  201. header = tag.expand
  202. unless header == previous_headers[name]
  203. previous_headers[name] = header
  204. unless restart.empty?
  205. restart.each do |n|
  206. previous_headers[n] = nil
  207. end
  208. end
  209. header
  210. end
  211. end
  212. desc %{
  213. Page attribute tags inside this tag refer to the parent of the current page.
  214. *Usage:*
  215. <pre><code><r:parent>...</r:parent></code></pre>
  216. }
  217. tag 'parent' do |tag|
  218. parent = tag.locals.page.parent
  219. tag.locals.page = parent
  220. tag.expand if parent
  221. end
  222. desc %{
  223. Renders the contained elements only if the current contextual page has a parent, i.e.
  224. is not the root page.
  225. *Usage:*
  226. <pre><code><r:if_parent>...</r:if_parent></code></pre>
  227. }
  228. tag 'if_parent' do |tag|
  229. parent = tag.locals.page.parent
  230. tag.expand if parent
  231. end
  232. desc %{
  233. Renders the contained elements only if the current contextual page has no parent, i.e.
  234. is the root page.
  235. *Usage:*
  236. <pre><code><r:unless_parent>...</r:unless_parent></code></pre>
  237. }
  238. tag 'unless_parent' do |tag|
  239. parent = tag.locals.page.parent
  240. tag.expand unless parent
  241. end
  242. desc %{
  243. Renders the contained elements only if the current contextual page has one or
  244. more child pages. The @status@ attribute limits the status of found child pages
  245. to the given status, the default is @"published"@. @status="all"@ includes all
  246. non-virtual pages regardless of status.
  247. *Usage:*
  248. <pre><code><r:if_children [status="published"]>...</r:if_children></code></pre>
  249. }
  250. tag 'if_children' do |tag|
  251. children = tag.locals.page.children.where(children_find_options(tag)[:conditions]).count
  252. tag.expand if children.positive?
  253. end
  254. desc %{
  255. Renders the contained elements only if the current contextual page has no children.
  256. The @status@ attribute limits the status of found child pages to the given status,
  257. the default is @"published"@. @status="all"@ includes all non-virtual pages
  258. regardless of status.
  259. *Usage:*
  260. <pre><code><r:unless_children [status="published"]>...</r:unless_children></code></pre>
  261. }
  262. tag 'unless_children' do |tag|
  263. children = tag.locals.page.children.where(children_find_options(tag)[:conditions]).count
  264. tag.expand unless children.positive?
  265. end
  266. desc %{
  267. Aggregates the children of multiple paths using the @paths@ attribute.
  268. Useful for combining many different sections/categories into a single
  269. feed or listing.
  270. *Usage*:
  271. <pre><code><r:aggregate paths="/section1; /section2; /section3"> ... </r:aggregate></code></pre>
  272. }
  273. tag 'aggregate' do |tag|
  274. required_attr(tag, 'paths', 'urls')
  275. paths = (tag.attr['paths'] || tag.attr['urls']).split(';').map(&:strip).reject(&:blank?).map { |u| clean_path u }
  276. parent_ids = paths.map { |u| Page.find_by_path(u) }.map(&:id)
  277. tag.locals.parent_ids = parent_ids
  278. tag.expand
  279. end
  280. desc %{
  281. Sets the scope to the individual aggregated page allowing you to
  282. iterate through each of the listed paths.
  283. *Usage*:
  284. <pre><code><r:aggregate:each paths="/section1; /section2; /section3"> ... </r:aggregate:each></code></pre>
  285. }
  286. tag 'aggregate:each' do |tag|
  287. aggregates = []
  288. tag.locals.aggregated_pages = tag.locals.parent_ids.map { |p| Page.find(p) }
  289. tag.locals.aggregated_pages.each do |aggregate_page|
  290. tag.locals.page = aggregate_page
  291. aggregates << tag.expand
  292. end
  293. aggregates.flatten.join
  294. end
  295. tag 'aggregate:each:children' do |tag|
  296. tag.locals.children = tag.locals.page.children
  297. tag.expand
  298. end
  299. tag 'aggregate:each:children:each' do |tag|
  300. options = children_find_options(tag)
  301. result = []
  302. children = tag.locals.children
  303. tag.locals.previous_headers = {}
  304. children.where(options).each do |item|
  305. tag.locals.child = item
  306. tag.locals.page = item
  307. result << tag.expand
  308. end
  309. result.flatten.join
  310. end
  311. tag 'aggregate:children' do |tag|
  312. tag.expand
  313. end
  314. desc %{
  315. Renders the total count of children of the aggregated pages. Accepts the
  316. same options as @<r:children:each />@.
  317. *Usage*:
  318. <pre><code><r:aggregate paths="/section1; /section2; /section3">
  319. <r:children:count />
  320. </r:aggregate></code></pre>
  321. }
  322. tag 'aggregate:children:count' do |tag|
  323. options = aggregate_children(tag)
  324. if ActiveRecord::Base.connection.adapter_name.downcase == 'postgresql'
  325. options[:group] = Page.columns.map { |c| c.name }.join(', ')
  326. Page.where(options).size
  327. else
  328. Page.where(options).count
  329. end
  330. end
  331. desc %{
  332. Renders the contained block for each child of the aggregated pages. Accepts the
  333. same options as the plain @<r:children:each />@.
  334. *Usage*:
  335. <pre><code><r:aggregate paths="/section1; /section2; /section3">
  336. <r:children:each>
  337. ...
  338. </r:children:each>
  339. </r:aggregate></code></pre>
  340. }
  341. tag 'aggregate:children:each' do |tag|
  342. render_children_with_pagination(tag, aggregate: true)
  343. end
  344. desc %{
  345. Renders the first child of the aggregated pages. Accepts the
  346. same options as @<r:children:each />@.
  347. *Usage*:
  348. <pre><code><r:aggregate paths="/section1; /section2; /section3">
  349. <r:children:first>
  350. ...
  351. </r:children:first>
  352. </r:aggregate></code></pre>
  353. }
  354. tag 'aggregate:children:first' do |tag|
  355. options = aggregate_children(tag)
  356. children = Page.where(options)
  357. if first = children.first
  358. tag.locals.page = first
  359. tag.expand
  360. end
  361. end
  362. desc %{
  363. Renders the last child of the aggregated pages. Accepts the
  364. same options as @<r:children:each />@.
  365. *Usage*:
  366. <pre><code><r:aggregate paths="/section1; /section2; /section3">
  367. <r:children:last>
  368. ...
  369. </r:children:last>
  370. </r:aggregate></code></pre>
  371. }
  372. tag 'aggregate:children:last' do |tag|
  373. options = aggregate_children(tag)
  374. children = Page.where(options)
  375. if last = children.last
  376. tag.locals.page = last
  377. tag.expand
  378. end
  379. end
  380. desc %{
  381. Renders the main content of a page. Use the @part@ attribute to select a specific
  382. page part. By default the @part@ attribute is set to body. Use the @inherit@
  383. attribute to specify that if a page does not have a content part by that name that
  384. the tag should render the parent's content part. By default @inherit@ is set to
  385. @false@. Use the @contextual@ attribute to force a part inherited from a parent
  386. part to be evaluated in the context of the child page. By default 'contextual'
  387. is set to true.
  388. *Usage:*
  389. <pre><code><r:content [part="part_name"] [inherit="true|false"] [contextual="true|false"] /></code></pre>
  390. }
  391. tag 'content' do |tag|
  392. page = tag.locals.page
  393. part_name = tag_part_name(tag)
  394. # Prevent simple and deep recursive rendering of the same page part
  395. rendering_parts = (tag.locals.rendering_parts ||= Hash.new { |h, k| h[k] = [] })
  396. if rendering_parts[page.id].include?(part_name)
  397. raise TagError.new(%{Recursion error: already rendering the `#{part_name}' part.})
  398. else
  399. rendering_parts[page.id] << part_name
  400. end
  401. inherit = boolean_attr_or_error(tag, 'inherit', false)
  402. part_page = page
  403. if inherit
  404. while part_page.part(part_name).nil? && (not part_page.parent.nil?)
  405. part_page = part_page.parent
  406. end
  407. end
  408. contextual = boolean_attr_or_error(tag, 'contextual', true)
  409. part = part_page.part(part_name)
  410. tag.locals.page = part_page unless contextual
  411. result = tag.globals.page.render_snippet(part) unless part.nil?
  412. rendering_parts[page.id].delete(part_name)
  413. result
  414. end
  415. desc %{
  416. Renders the containing elements if all of the listed parts exist on a page.
  417. By default the @part@ attribute is set to @body@, but you may list more than one
  418. part by separating them with a comma. Setting the optional @inherit@ to true will
  419. search ancestors independently for each part. By default @inherit@ is set to @false@.
  420. When listing more than one part, you may optionally set the @find@ attribute to @any@
  421. so that it will render the containing elements if any of the listed parts are found.
  422. By default the @find@ attribute is set to @all@.
  423. *Usage:*
  424. <pre><code><r:if_content [part="part_name, other_part"] [inherit="true"] [find="any"]>...</r:if_content></code></pre>
  425. }
  426. tag 'if_content' do |tag|
  427. part_name = tag_part_name(tag)
  428. parts_arr = part_name.split(',')
  429. inherit = boolean_attr_or_error(tag, 'inherit', 'false')
  430. find = attr_or_error(tag, attribute_name: 'find', default: 'all', values: 'any, all')
  431. expandable = true
  432. one_found = false
  433. parts_arr.each do |name|
  434. part_page = tag.locals.page
  435. name.strip!
  436. if inherit
  437. while part_page.part(name).nil? && (not part_page.parent.nil?)
  438. part_page = part_page.parent
  439. end
  440. end
  441. expandable = false if part_page.part(name).nil?
  442. one_found ||= true if !part_page.part(name).nil?
  443. end
  444. expandable = true if (find == 'any') && one_found
  445. tag.expand if expandable
  446. end
  447. desc %{
  448. The opposite of the @if_content@ tag. It renders the contained elements if all of the
  449. specified parts do not exist. Setting the optional @inherit@ to true will search
  450. ancestors independently for each part. By default @inherit@ is set to @false@.
  451. When listing more than one part, you may optionally set the @find@ attribute to @any@
  452. so that it will not render the containing elements if any of the listed parts are found.
  453. By default the @find@ attribute is set to @all@.
  454. *Usage:*
  455. <pre><code><r:unless_content [part="part_name, other_part"] [inherit="false"] [find="any"]>...</r:unless_content></code></pre>
  456. }
  457. tag 'unless_content' do |tag|
  458. part_name = tag_part_name(tag)
  459. parts_arr = part_name.split(',')
  460. inherit = boolean_attr_or_error(tag, 'inherit', false)
  461. find = attr_or_error(tag, attribute_name: 'find', default: 'all', values: 'any, all')
  462. expandable = true
  463. all_found = true
  464. parts_arr.each do |name|
  465. part_page = tag.locals.page
  466. name.strip!
  467. if inherit
  468. while part_page.part(name).nil? && (not part_page.parent.nil?)
  469. part_page = part_page.parent
  470. end
  471. end
  472. expandable = false if !part_page.part(name).nil?
  473. all_found = false if part_page.part(name).nil?
  474. end
  475. if (all_found == false) && (find == 'all')
  476. expandable = true
  477. end
  478. tag.expand if expandable
  479. end
  480. desc %{
  481. Renders the containing elements only if the page's path matches the regular expression
  482. given in the @matches@ attribute. If the @ignore_case@ attribute is set to false, the
  483. match is case sensitive. By default, @ignore_case@ is set to true.
  484. *Usage:*
  485. <pre><code><r:if_path matches="regexp" [ignore_case="true|false"]>...</r:if_path></code></pre>
  486. }
  487. tag 'if_path' do |tag|
  488. required_attr(tag, 'matches')
  489. regexp = build_regexp_for(tag, 'matches')
  490. unless tag.locals.page.path.match(regexp).nil?
  491. tag.expand
  492. end
  493. end
  494. desc %{
  495. The opposite of the @if_path@ tag.
  496. *Usage:*
  497. <pre><code><r:unless_path matches="regexp" [ignore_case="true|false"]>...</r:unless_path></code></pre>
  498. }
  499. tag 'unless_path' do |tag|
  500. required_attr(tag, 'matches')
  501. regexp = build_regexp_for(tag, 'matches')
  502. if tag.locals.page.path.match(regexp).nil?
  503. tag.expand
  504. end
  505. end
  506. desc %{
  507. Renders the contained elements if the current contextual page is either the actual page or one of its parents.
  508. This is typically used inside another tag (like &lt;r:children:each&gt;) to add conditional mark-up if the child element is or descends from the current page.
  509. *Usage:*
  510. <pre><code>...</code></pre>
  511. }
  512. tag 'unless_ancestor_or_self' do |tag|
  513. tag.expand unless (tag.globals.page.ancestors + [tag.globals.page]).include?(tag.locals.page)
  514. end
  515. desc %{
  516. Renders the contained elements if the current contextual page is also the actual page.
  517. This is typically used inside another tag (like &lt;r:children:each&gt;) to add conditional mark-up if the child element is the current page.
  518. *Usage:*
  519. <pre><code><r:if_self>...</r:if_self></code></pre>
  520. }
  521. tag 'if_self' do |tag|
  522. tag.expand if tag.locals.page == tag.globals.page
  523. end
  524. desc %{
  525. Renders the contained elements unless the current contextual page is also the actual page.
  526. This is typically used inside another tag (like &lt;r:children:each&gt;) to add conditional mark-up unless the child element is the current page.
  527. *Usage:*
  528. <pre><code><r:unless_self>...</r:unless_self></code></pre>
  529. }
  530. tag 'unless_self' do |tag|
  531. tag.expand unless tag.locals.page == tag.globals.page
  532. end
  533. desc %{
  534. Renders the name of the author of the current page.
  535. }
  536. tag 'author' do |tag|
  537. page = tag.locals.page
  538. if author = page.created_by
  539. author.name
  540. end
  541. end
  542. desc %{
  543. Renders the date based on the current page (by default when it was published or created).
  544. The format attribute uses the same formating codes used by the Ruby @strftime@ function.
  545. By default it's set to @%A, %B %d, %Y@. You may also use the string @rfc1123@ as a shortcut
  546. for @%a, %d %b %Y %H:%M:%S GMT@ (non-localized). The @for@ attribute selects which date to
  547. render. Valid options are @published_at@, @created_at@, @updated_at@, and @now@. @now@ will
  548. render the current date/time, regardless of the page.
  549. *Usage:*
  550. <pre><code><r:date [format="%A, %B %d, %Y"] [for="published_at"]/></code></pre>
  551. }
  552. tag 'date' do |tag|
  553. page = tag.locals.page
  554. format = (tag.attr['format'] || '%A, %B %d, %Y')
  555. time_attr = tag.attr['for']
  556. date = if time_attr
  557. if time_attr == 'now'
  558. Time.zone.now
  559. elsif Page.date_column_names.include?(time_attr)
  560. page[time_attr]
  561. else
  562. raise TagError, "Invalid value for 'for' attribute."
  563. end
  564. else
  565. page.published_at || page.created_at
  566. end
  567. case format
  568. when 'rfc1123'
  569. CGI.rfc1123_date(date.to_time)
  570. else
  571. @i18n_date_format_keys ||= begin
  572. begin
  573. I18n.config.backend.send(:translations)[I18n.locale][:date][:formats].keys
  574. rescue StandardError
  575. []
  576. end
  577. end
  578. format = @i18n_date_format_keys.include?(format.to_sym) ? format.to_sym : format
  579. I18n.l date, format: format
  580. end
  581. end
  582. desc %{
  583. Inside this tag all page related tags refer to the page found at the @path@ attribute.
  584. @path@s may be relative or absolute paths.
  585. *Usage:*
  586. <pre><code><r:find path="value_to_find">...</r:find></code></pre>
  587. }
  588. tag 'find' do |tag|
  589. required_attr(tag, 'path', 'url')
  590. path = tag.attr['path'] || tag.attr['url']
  591. found = Page.find_by_path(absolute_path_for(tag.locals.page.path, path))
  592. if page_found?(found)
  593. tag.locals.page = found
  594. tag.expand
  595. end
  596. end
  597. desc %{
  598. Randomly renders one of the options specified by the @option@ tags.
  599. *Usage:*
  600. <pre><code><r:random>
  601. <r:option>...</r:option>
  602. <r:option>...</r:option>
  603. ...
  604. <r:random>
  605. </code></pre>
  606. }
  607. tag 'random' do |tag|
  608. tag.locals.random = []
  609. tag.expand
  610. options = tag.locals.random
  611. option = options[rand(options.size)]
  612. option
  613. end
  614. tag 'random:option' do |tag|
  615. items = tag.locals.random
  616. items << tag.expand
  617. end
  618. desc %{
  619. Nothing inside a set of hide tags is rendered.
  620. *Usage:*
  621. <pre><code><r:hide>...</r:hide></code></pre>
  622. }
  623. tag 'hide' do |tag|
  624. end
  625. desc %{
  626. Escapes angle brackets, etc. for rendering in an HTML document.
  627. *Usage:*
  628. <pre><code><r:escape_html>...</r:escape_html></code></pre>
  629. }
  630. tag 'escape_html' do |tag|
  631. CGI.escapeHTML(tag.expand)
  632. end
  633. desc %{
  634. Renders a list of links specified in the @paths@ attribute according to three
  635. states:
  636. * @normal@ specifies the normal state for the link
  637. * @here@ specifies the state of the link when the path matches the current
  638. page's PATH
  639. * @selected@ specifies the state of the link when the current page matches
  640. is a child of the specified path
  641. # @if_last@ renders its contents within a @normal@, @here@ or
  642. @selected@ tag if the item is the last in the navigation elements
  643. # @if_first@ renders its contents within a @normal@, @here@ or
  644. @selected@ tag if the item is the first in the navigation elements
  645. The @between@ tag specifies what should be inserted in between each of the links.
  646. *Usage:*
  647. <pre><code><r:navigation paths="[Title: path | Title: path | ...]">
  648. <r:normal><a href="<r:path />"><r:title /></a></r:normal>
  649. <r:here><strong><r:title /></strong></r:here>
  650. <r:selected><strong><a href="<r:path />"><r:title /></a></strong></r:selected>
  651. <r:between> | </r:between>
  652. </r:navigation>
  653. </code></pre>
  654. }
  655. tag 'navigation' do |tag|
  656. hash = tag.locals.navigation = {}
  657. tag.expand
  658. raise TagError.new("`navigation' tag must include a `normal' tag") unless hash.has_key? :normal
  659. # ActiveSupport::Deprecation.warn("The 'urls' attribute of the r:navigation tag has been deprecated in favour of 'paths'. Please update your site.") if tag.attr['urls']
  660. result = []
  661. pairs = (tag.attr['paths'] || tag.attr['urls']).to_s.split('|').map do |pair|
  662. parts = pair.split(':')
  663. value = parts.pop
  664. key = parts.join(':')
  665. [key.strip, value.strip]
  666. end
  667. pairs.each_with_index do |(title, path), i|
  668. compare_path = remove_trailing_slash(path)
  669. page_path = remove_trailing_slash(path)
  670. hash[:title] = title
  671. hash[:path] = path
  672. tag.locals.first_child = i.zero?
  673. tag.locals.last_child = i == pairs.length - 1
  674. result << case page_path
  675. when compare_path
  676. (hash[:here] || hash[:selected] || hash[:normal]).call
  677. when Regexp.compile('^' + Regexp.quote(path))
  678. (hash[:selected] || hash[:normal]).call
  679. else
  680. hash[:normal].call
  681. end
  682. end
  683. between = hash.has_key?(:between) ? hash[:between].call : ' '
  684. result.reject { |i| i.blank? }.join(between)
  685. end
  686. %i[normal here selected between].each do |symbol|
  687. tag "navigation:#{symbol}" do |tag|
  688. hash = tag.locals.navigation
  689. hash[symbol] = tag.block
  690. end
  691. end
  692. %i[title path].each do |symbol|
  693. tag "navigation:#{symbol}" do |tag|
  694. hash = tag.locals.navigation
  695. hash[symbol]
  696. end
  697. end
  698. tag 'navigation:path' do |tag|
  699. hash = tag.locals.navigation
  700. # ActiveSupport::Deprecation.warn("The 'r:navigation:url' tag has been deprecated in favour of 'r:navigation:path'. Please update your site.")
  701. hash[:path]
  702. end
  703. desc %{
  704. Renders the containing elements if the element is the first
  705. in the navigation list
  706. *Usage:*
  707. <pre><code><r:normal><r:if_first>...</r:if_first></r:normal></code></pre>
  708. }
  709. tag 'navigation:if_first' do |tag|
  710. tag.expand if tag.locals.first_child
  711. end
  712. desc %{
  713. Renders the containing elements unless the element is the first
  714. in the navigation list
  715. *Usage:*
  716. <pre><code><r:normal><r:unless_first>...</r:unless_first></r:normal></code></pre>
  717. }
  718. tag 'navigation:unless_first' do |tag|
  719. tag.expand unless tag.locals.first_child
  720. end
  721. desc %{
  722. Renders the containing elements unless the element is the last
  723. in the navigation list
  724. *Usage:*
  725. <pre><code><r:normal><r:unless_last>...</r:unless_last></r:normal></code></pre>
  726. }
  727. tag 'navigation:unless_last' do |tag|
  728. tag.expand unless tag.locals.last_child
  729. end
  730. desc %{
  731. Renders the containing elements if the element is the last
  732. in the navigation list
  733. *Usage:*
  734. <pre><code><r:normal><r:if_last>...</r:if_last></r:normal></code></pre>
  735. }
  736. tag 'navigation:if_last' do |tag|
  737. tag.expand if tag.locals.last_child
  738. end
  739. tag 'site' do |tag|
  740. tag.expand
  741. end
  742. desc %{
  743. Returns TrustyCms::Config['site.title'] as configured under the Settings tab.
  744. }
  745. tag 'site:title' do |_tag|
  746. TrustyCms::Config['site.title']
  747. end
  748. desc %{
  749. Returns TrustyCms::Config['site.host'] as configured under the Settings tab.
  750. }
  751. tag 'site:host' do |_tag|
  752. TrustyCms::Config['site.host']
  753. end
  754. desc %{
  755. Returns TrustyCms::Config['dev.host'] as configured under the Settings tab.
  756. }
  757. tag 'site:dev_host' do |_tag|
  758. TrustyCms::Config['dev.host']
  759. end
  760. tag 'meta' do |tag|
  761. if tag.double?
  762. tag.expand
  763. else
  764. tag.render('description', tag.attr) + tag.render('keywords', tag.attr)
  765. end
  766. end
  767. tag 'meta:description' do |tag|
  768. show_tag = tag.attr['tag'] != 'false' || false
  769. description = CGI.escapeHTML(tag.locals.page.field(:description).try(:content)) if tag.locals.page.field(:description)
  770. if show_tag
  771. "<meta name=\"description\" content=\"#{description}\" />"
  772. else
  773. description
  774. end
  775. end
  776. tag 'meta:keywords' do |tag|
  777. show_tag = tag.attr['tag'] != 'false' || false
  778. keywords = CGI.escapeHTML(tag.locals.page.field(:keywords).try(:content)) if tag.locals.page.field(:keywords)
  779. if show_tag
  780. "<meta name=\"keywords\" content=\"#{keywords}\" />"
  781. else
  782. keywords
  783. end
  784. end
  785. desc 'Widget of sharing icons'
  786. tag 'rad_share_widget' do |tag|
  787. attributes = tag.attr.to_options
  788. url = attributes[:url].nil? ? request.url : attributes[:url]
  789. message = attributes[:message].nil? ? "Check out #{tag.locals.page.title}." : attributes[:message]
  790. email_subject = attributes[:email_subject].nil? ? tag.locals.page.title : attributes[:email_subject]
  791. email_message = attributes[:email_message].nil? ? "I thought you might be interested in this: #{url}" : "#{attributes[:email_message]} #{url}"
  792. email_action_url = attributes[:email_action_url].nil? ? '/rad_social/mail' : attributes[:email_action_url]
  793. request.env['action_controller.instance'].render_to_string partial: 'widget/horizontal_widget',
  794. locals: { url: url,
  795. message: message,
  796. email_subject: email_subject,
  797. email_message: email_message,
  798. email_action_url: email_action_url }
  799. end
  800. private
  801. def render_children_with_pagination(tag, opts = {})
  802. if opts[:aggregate]
  803. findable = Page
  804. options = aggregate_children(tag)
  805. else
  806. findable = tag.locals.children
  807. options = children_find_options(tag)
  808. end
  809. paging = pagination_find_options(tag)
  810. result = []
  811. tag.locals.previous_headers = {}
  812. displayed_children = paging ? findable.paginate(options.merge(paging)) : findable.all.where(options[:conditions]).order(options[:order])
  813. displayed_children.each_with_index do |item, i|
  814. tag.locals.child = item
  815. tag.locals.page = item
  816. tag.locals.first_child = i == 0
  817. tag.locals.last_child = i == displayed_children.length - 1
  818. result << tag.expand
  819. end
  820. if paging && displayed_children.total_pages > 1
  821. tag.locals.paginated_list = displayed_children
  822. result << tag.render('pagination', tag.attr.dup)
  823. end
  824. result.flatten.join
  825. end
  826. def children_find_options(tag)
  827. attr = tag.attr.symbolize_keys
  828. options = {}
  829. %i[limit offset].each do |symbol|
  830. if number = attr[symbol]
  831. if number =~ /^\d+$/
  832. options[symbol] = number.to_i
  833. else
  834. raise TagError.new("`#{symbol}' attribute must be a positive number")
  835. end
  836. end
  837. end
  838. by = (attr[:by] || 'published_at').strip
  839. order = (attr[:order] || 'asc').strip
  840. order_string = ''
  841. if attributes.keys.include?(by)
  842. order_string << by
  843. else
  844. raise TagError.new("`by' attribute of `each' tag must be set to a valid field name")
  845. end
  846. if order =~ /^(asc|desc)$/i
  847. order_string << " #{$1.upcase}"
  848. else
  849. raise TagError.new(%{`order' attribute of `each' tag must be set to either "asc" or "desc"})
  850. end
  851. options[:order] = order_string
  852. status = (attr[:status] || (dev?(tag.globals.page.request) ? 'all' : 'published')).downcase
  853. if status == 'all'
  854. options[:conditions] = ['virtual = ?', false]
  855. else
  856. stat = Status[status]
  857. if stat.nil?
  858. raise TagError.new(%{`status' attribute of `each' tag must be set to a valid status})
  859. else
  860. options[:conditions] = ['(virtual = ?) and (status_id = ?)', false, stat.id]
  861. end
  862. end
  863. options
  864. end
  865. def aggregate_children(tag)
  866. options = children_find_options(tag)
  867. parent_ids = tag.locals.parent_ids
  868. conditions = options[:conditions]
  869. conditions.first << ' AND parent_id IN (?)'
  870. conditions << parent_ids
  871. options
  872. end
  873. def pagination_find_options(tag)
  874. attr = tag.attr.symbolize_keys
  875. if attr[:paginated] == 'true'
  876. pagination_parameters.merge(attr.slice(:per_page))
  877. else
  878. false
  879. end
  880. end
  881. def will_paginate_options(tag)
  882. attr = tag.attr.symbolize_keys
  883. if attr[:paginated] == 'true'
  884. attr.slice(:class, :previous_label, :next_label, :inner_window, :outer_window, :separator, :per_page).merge({ renderer: TrustyCms::Pagination::LinkRenderer.new(tag.globals.page.path) })
  885. else
  886. {}
  887. end
  888. end
  889. def remove_trailing_slash(string)
  890. string =~ %r{^(.*?)/$} ? $1 : string
  891. end
  892. def tag_part_name(tag)
  893. tag.attr['part'] || 'body'
  894. end
  895. def build_regexp_for(tag, attribute_name)
  896. ignore_case = tag.attr.has_key?('ignore_case') && tag.attr['ignore_case'] == 'false' ? nil : true
  897. begin
  898. regexp = Regexp.new(tag.attr['matches'], ignore_case)
  899. rescue RegexpError => e
  900. raise TagError.new("Malformed regular expression in `#{attribute_name}' argument of `#{tag.name}' tag: #{e.message}")
  901. end
  902. regexp
  903. end
  904. def relative_url_for(url, _request)
  905. File.join(ActionController::Base.relative_url_root || '', url)
  906. end
  907. def absolute_path_for(base_path, new_path)
  908. if new_path.first == '/'
  909. new_path
  910. else
  911. File.expand_path(File.join(base_path, new_path))
  912. end
  913. end
  914. def page_found?(page)
  915. page && !(FileNotFoundPage === page)
  916. end
  917. def boolean_attr_or_error(tag, attribute_name, default)
  918. attribute = attr_or_error(tag, attribute_name: attribute_name, default: default.to_s, values: 'true, false')
  919. attribute.to_s.downcase == 'true'
  920. end
  921. def attr_or_error(tag, options = {})
  922. attribute_name = options[:attribute_name].to_s
  923. default = options[:default]
  924. values = options[:values].split(',').map!(&:strip)
  925. attribute = (tag.attr[attribute_name] || default).to_s
  926. raise TagError.new(%{`#{attribute_name}' attribute of `#{tag.name}' tag must be one of: #{values.join(', ')}}) unless values.include?(attribute)
  927. attribute
  928. end
  929. def required_attr(tag, *attribute_names)
  930. attr_collection = attribute_names.map { |a| "`#{a}'" }.join(' or ')
  931. raise TagError.new("`#{tag.name}' tag must contain a #{attr_collection} attribute.") if (tag.attr.keys & attribute_names).blank?
  932. end
  933. def dev?(request)
  934. return false if request.nil?
  935. if dev_host = TrustyCms::Config['dev.host']
  936. dev_host == request.host
  937. else
  938. request.host =~ /^dev\./
  939. end
  940. end
  941. end

app/models/status.rb

0.0% lines covered

30 relevant lines. 0 lines covered and 30 lines missed.
    
  1. class Status
  2. attr_accessor :id, :name
  3. def initialize(options = {})
  4. options = options.symbolize_keys
  5. @id = options[:id]
  6. @name = options[:name]
  7. end
  8. def symbol
  9. @name.to_s.downcase.intern
  10. end
  11. def self.[](value)
  12. @@statuses.find { |status| status.symbol == value.to_s.downcase.intern }
  13. end
  14. def self.find(id)
  15. @@statuses.find { |status| status.id.to_s == id.to_s }
  16. end
  17. def self.selectable
  18. @@statuses
  19. end
  20. def self.selectable_values
  21. selectable.map(&:name)
  22. end
  23. @@statuses = [
  24. Status.new(id: 1, name: 'Draft'),
  25. Status.new(id: 50, name: 'Reviewed'),
  26. Status.new(id: 90, name: 'Scheduled'),
  27. Status.new(id: 100, name: 'Published'),
  28. Status.new(id: 101, name: 'Hidden'),
  29. ]
  30. end

app/models/text_filter.rb

62.5% lines covered

16 relevant lines. 10 lines covered and 6 lines missed.
    
  1. 1 class TextFilter
  2. 1 include Simpleton
  3. 1 include Annotatable
  4. 1 annotate :filter_name, :description
  5. 1 def filter(text)
  6. text
  7. end
  8. 1 class << self
  9. 1 def inherited(subclass)
  10. subclass.filter_name = subclass.name.to_name('Filter')
  11. end
  12. 1 def filter(text)
  13. instance.filter(text)
  14. end
  15. 1 def descendants_names
  16. descendants.map { |s| s.filter_name }.sort
  17. end
  18. 1 def find_descendant(filter_name)
  19. descendants.each do |s|
  20. return s if s.filter_name == filter_name
  21. end
  22. nil
  23. end
  24. end
  25. end

app/models/trusty_cms/config.rb

0.0% lines covered

152 relevant lines. 0 lines covered and 152 lines missed.
    
  1. module TrustyCms
  2. class << self
  3. def config_definitions
  4. @config_definitions ||= {}
  5. end
  6. def config_definitions=(definitions)
  7. @config_definitions = definitions
  8. end
  9. end
  10. class Config < ActiveRecord::Base
  11. require 'trusty_cms/config/definition'
  12. #
  13. # The TrustyCms.config model class is stored in the database (and cached) but emulates a hash
  14. # with simple bracket methods that allow you to get and set values like so:
  15. #
  16. # TrustyCms.config['setting.name'] = 'value'
  17. # TrustyCms.config['setting.name'] #=> "value"
  18. #
  19. # Config entries can be used freely as general-purpose global variables unless a definition
  20. # has been given for that key, in which case restrictions and defaults may apply. The restrictions
  21. # can take the form of validations, requirements, permissions or permitted options. They are
  22. # declared by calling TrustyCms::Config#define:
  23. #
  24. # # setting must be either 'foo', 'bar' or 'blank'
  25. # define('admin.name', :select_from => ['foo', 'bar'])
  26. #
  27. # # setting is (and must be) chosen from the names of currently available layouts
  28. # define('shop.layout', :select_from => lambda { Layout.all.map{|l| [l.name,l.id]} }, :alow_blank => false)
  29. #
  30. # # setting cannot be changed at runtime
  31. # define('setting.important', :default => "something", :allow_change => false)
  32. #
  33. # Which almost always happens in a block like this:
  34. #
  35. # TrustyCms.config do |config|
  36. # config.namespace('user', :allow_change => true) do |user|
  37. # user.define 'allow_password_reset?', :default => true
  38. # end
  39. # end
  40. #
  41. # or in an extension. TrustyCms currently defines the following settings and makes them editable by
  42. # admin users on the site configuration page:
  43. #
  44. # admin.title :: the title of the admin system
  45. # admin.subtitle :: the subtitle of the admin system
  46. # defaults.page.parts :: a comma separated list of default page parts
  47. # defaults.page.status :: a string representation of the default page status
  48. # defaults.page.filter :: the default filter to use on new page parts
  49. # defaults.page.fields :: a comma separated list of the default page fields
  50. # defaults.snippet.filter :: the default filter to use on new snippets
  51. # dev.host :: the hostname where draft pages are viewable
  52. # local.timezone :: the timezone name (`rake -D time` for full list)
  53. # used to correct displayed times
  54. # page.edit.published_date? :: when true, shows the datetime selector
  55. # for published date on the page edit screen
  56. #
  57. # Helper methods are defined in ConfigurationHelper that will display config entry values
  58. # or edit fields:
  59. #
  60. # # to display label and value, where label comes from looking up the config key in the active locale
  61. # show_setting('admin.name')
  62. #
  63. # # to display an appropriate checkbox, text field or select box with label as above:
  64. # edit_setting('admin.name)
  65. #
  66. self.table_name = 'config'
  67. after_save :update_cache
  68. attr_reader :definition
  69. class ConfigError < RuntimeError; end
  70. class << self
  71. def [](key)
  72. if database_exists?
  73. if table_exists?
  74. unless TrustyCms::Config.cache_file_exists?
  75. TrustyCms::Config.ensure_cache_file
  76. TrustyCms::Config.initialize_cache
  77. end
  78. TrustyCms::Config.initialize_cache if TrustyCms::Config.stale_cache?
  79. config_cache = Rails.cache.read('TrustyCms::Config')
  80. config_cache ? config_cache[key] : nil
  81. end
  82. end
  83. end
  84. def []=(key, value)
  85. if database_exists?
  86. if table_exists?
  87. setting = where(key: key).first_or_initialize
  88. setting.value = value
  89. end
  90. end
  91. end
  92. def database_exists?
  93. ActiveRecord::Base.connection
  94. rescue ActiveRecord::NoDatabaseError
  95. false
  96. else
  97. true
  98. end
  99. def to_hash
  100. Hash[*all.map { |pair| [pair.key, pair.value] }.flatten]
  101. end
  102. def initialize_cache
  103. TrustyCms::Config.ensure_cache_file
  104. Rails.cache.write('TrustyCms::Config', TrustyCms::Config.to_hash)
  105. Rails.cache.write('TrustyCms.cache_mtime', File.mtime(cache_file))
  106. Rails.cache.silence!
  107. end
  108. def cache_file_exists?
  109. File.file?(cache_file)
  110. end
  111. def stale_cache?
  112. return true unless TrustyCms::Config.cache_file_exists?
  113. Rails.cache.read('TrustyCms.cache_mtime') != File.mtime(cache_file)
  114. end
  115. def ensure_cache_file
  116. FileUtils.mkpath(cache_path)
  117. FileUtils.touch(cache_file)
  118. end
  119. def cache_path
  120. "#{Rails.root}/tmp"
  121. end
  122. def cache_file
  123. File.join(cache_path, 'trusty_config_cache.txt')
  124. end
  125. def site_settings
  126. @site_settings ||= %w{site.title site.host dev.host local.timezone}
  127. end
  128. def default_settings
  129. @default_settings ||= %w{defaults.locale defaults.page.filter defaults.page.parts defaults.page.fields defaults.page.status}
  130. end
  131. def user_settings
  132. @user_settings ||= ['user.allow_password_reset?']
  133. end
  134. # A convenient drying method for specifying a prefix and options common to several settings.
  135. #
  136. # TrustyCms.config do |config|
  137. # config.namespace('secret', :allow_display => false) do |secret|
  138. # secret.define('identity', :default => 'batman') # defines 'secret.identity'
  139. # secret.define('lair', :default => 'batcave') # defines 'secret.lair'
  140. # secret.define('longing', :default => 'vindication') # defines 'secret.longing'
  141. # end
  142. # end
  143. #
  144. def namespace(prefix, options = {}, &block)
  145. prefix = [options[:prefix], prefix].join('.') if options[:prefix]
  146. with_options(options.merge(prefix: prefix), &block)
  147. end
  148. # Declares a setting definition that will constrain and support the use of a particular config entry.
  149. #
  150. # define('setting.key', options)
  151. #
  152. # Can take several options:
  153. # * :default is the value that will be placed in the database if none has been set already
  154. # * :type can be :string, :boolean or :integer. Note that all settings whose key ends in ? are considered boolean.
  155. # * :select_from should be a list or hash suitable for passing to options_for_select, or a block that will return such a list at runtime
  156. # * :validate_with should be a block that will receive a value and return true or false. Validations are also implied by type or select_from.
  157. # * :allow_blank should be false if the config item must not be blank or nil
  158. # * :allow_change should be false if the config item can only be set, not changed. Add a default to specify an unchanging config entry.
  159. # * :allow_display should be false if the config item should not be showable in radius tags
  160. #
  161. # TrustyCms.config do |config|
  162. # config.define 'defaults.locale', :select_from => lambda { TrustyCms::AvailableLocales.locales }, :allow_blank => true
  163. # config.define 'defaults.page.parts', :default => "Body,Extended"
  164. # ...
  165. # end
  166. #
  167. # It's also possible to reuse a definition by passing it to define:
  168. #
  169. # choose_layout = TrustyCms::Config::Definition.new(:select_from => lambda {Layout.all.map{|l| [l.name, l.d]}})
  170. # define "my.layout", choose_layout
  171. # define "your.layout", choose_layout
  172. #
  173. # but at the moment that's only done in testing.
  174. #
  175. def define(key, options = {})
  176. called_from = caller.grep(/\/initializers\//).first
  177. if options.is_a? TrustyCms::Config::Definition
  178. definition = options
  179. else
  180. key = [options[:prefix], key].join('.') if options[:prefix]
  181. end
  182. definition ||= TrustyCms::Config::Definition.new(options.merge(definer: called_from))
  183. definitions[key] = definition
  184. if self[key].nil? && !definition.default.nil?
  185. begin
  186. self[key] = definition.default
  187. rescue ActiveRecord::RecordInvalid
  188. raise LoadError, "Default configuration invalid: value '#{definition.default}' is not allowed for '#{key}'"
  189. end
  190. end
  191. end
  192. def definitions
  193. TrustyCms.config_definitions
  194. end
  195. def definition_for(key)
  196. definitions[key] ||= TrustyCms::Config::Definition.new(empty: true)
  197. end
  198. end
  199. # The usual way to use a config item:
  200. #
  201. # TrustyCms.config['key'] = value
  202. #
  203. # is equivalent to this:
  204. #
  205. # TrustyCms::Config.find_or_create_by_key('key').value = value
  206. #
  207. # Calling value= also applies any validations and restrictions that are found in the associated definition.
  208. # so this will raise a ConfigError if you try to change a protected config entry or a RecordInvalid if you
  209. # set a value that is not among those permitted.
  210. #
  211. def value=(param)
  212. newvalue = param.to_s
  213. if newvalue != self[:value]
  214. raise ConfigError, "#{key} cannot be changed" unless settable? || self[:value].blank?
  215. self[:value] = if boolean?
  216. newvalue == '1' || newvalue == 'true' ? 'true' : 'false'
  217. else
  218. newvalue
  219. end
  220. save!
  221. end
  222. self[:value]
  223. end
  224. # Requesting a config item:
  225. #
  226. # key = TrustyCms.config['key']
  227. #
  228. # is equivalent to this:
  229. #
  230. # key = TrustyCms::Config.find_or_create_by_key('key').value
  231. #
  232. # If the config item is boolean the response will be true or false. For items with :type => :integer it will be an integer,
  233. # for everything else a string.
  234. #
  235. def value
  236. if boolean?
  237. checked?
  238. else
  239. self[:value]
  240. end
  241. end
  242. # Returns the definition associated with this config item. If none has been declared this will be an empty definition
  243. # that does not restrict use.
  244. #
  245. def definition
  246. @definition ||= self.class.definition_for(key)
  247. end
  248. # Returns true if the item key ends with '?' or the definition specifies :type => :boolean.
  249. #
  250. def boolean?
  251. definition.boolean? || key.ends_with?('?')
  252. end
  253. # Returns true if the item is boolean and true.
  254. #
  255. def checked?
  256. return nil if self[:value].nil?
  257. boolean? && self[:value] == 'true'
  258. end
  259. # Returns true if the item defintion includes a :select_from parameter that limits the range of permissible options.
  260. #
  261. def selector?
  262. definition.selector?
  263. end
  264. # Returns a name corresponding to the current setting value, if the setting definition includes a select_from parameter.
  265. #
  266. def selected_value
  267. definition.selected(value)
  268. end
  269. def update_cache
  270. TrustyCms::Config.initialize_cache
  271. end
  272. delegate :default, :type, :allow_blank?, :hidden?, :visible?, :settable?, :selection, :notes, :units, to: :definition
  273. def validate
  274. definition.validate(self)
  275. end
  276. end
  277. end

app/models/trusty_cms/page_response_cache_director.rb

0.0% lines covered

34 relevant lines. 0 lines covered and 34 lines missed.
    
  1. module TrustyCms
  2. class PageResponseCacheDirector
  3. def initialize(page, listener)
  4. @page = page
  5. @listener = listener
  6. end
  7. def set_cache_control
  8. cacheable? ? cacheable_response : non_cacheable_response
  9. end
  10. class << self
  11. def cache_timeout
  12. @cache_timeout ||= 5.minutes
  13. end
  14. def cache_timeout=(val)
  15. @cache_timeout = val
  16. end
  17. end
  18. private
  19. def non_cacheable_response
  20. @listener.set_expiry nil, :private => true, 'no-cache' => true
  21. @listener.set_etag('')
  22. end
  23. def cacheable_response
  24. timeout = self.class.cache_timeout
  25. if @page.respond_to?(:cache_timeout)
  26. timeout = @page.cache_timeout
  27. end
  28. @listener.set_expiry timeout, public: true, private: false
  29. end
  30. def cacheable?
  31. @listener.cacheable_request? && @page.cache?
  32. end
  33. end
  34. end

app/models/user.rb

0.0% lines covered

55 relevant lines. 0 lines covered and 55 lines missed.
    
  1. class User < ActiveRecord::Base
  2. has_many :pages, foreign_key: :created_by_id
  3. self.table_name = 'admins'
  4. # :confirmable, :lockable, :timeoutable and :omniauthable
  5. devise :database_authenticatable, :registerable,
  6. :recoverable, :rememberable, :trackable, :validatable
  7. alias_attribute :created_by_id, :id
  8. attr_accessor :skip_password_validation
  9. validate :password_complexity
  10. # Default Order
  11. default_scope { order('last_name') }
  12. # Associations
  13. belongs_to :created_by, class_name: 'User'
  14. belongs_to :updated_by, class_name: 'User'
  15. has_many :admins_sites, foreign_key: 'admin_id', class_name: 'AdminsSite', dependent: :destroy
  16. has_many :sites, through: :admins_sites
  17. # Roles
  18. # Admin - all permissions
  19. # Editor - all permissions except for users, sites editing
  20. # Content Editor - all permissions except for users, sites, publishing and deleting
  21. def role?(role)
  22. case role
  23. when :admin
  24. admin?
  25. when :designer
  26. designer?
  27. when :content_editor
  28. content_editor?
  29. else
  30. false
  31. end
  32. end
  33. def admin?
  34. admin
  35. end
  36. def designer?
  37. designer
  38. end
  39. def editor?
  40. designer
  41. end
  42. def content_editor?
  43. content_editor
  44. end
  45. def scoped_site?
  46. sites.present?
  47. end
  48. def locale
  49. 'en'
  50. end
  51. def name
  52. "#{first_name} #{last_name}"
  53. end
  54. def password_required?
  55. return false if skip_password_validation
  56. super
  57. end
  58. def password_complexity
  59. return false if password.blank? || password =~ /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,70}$/
  60. errors.add :password, 'Complexity requirement not met. Length should be 12 characters and include: 1 uppercase, 1 lowercase, 1 digit and 1 special character.'
  61. end
  62. end

app/models/user_action_observer.rb

0.0% lines covered

19 relevant lines. 0 lines covered and 19 lines missed.
    
  1. class UserActionObserver < ActiveRecord::Observer
  2. observe User, Page, Layout
  3. def current_user=(user)
  4. self.class.current_user = user
  5. end
  6. def self.current_user=(user)
  7. Thread.current[:current_user] = user
  8. end
  9. def current_user
  10. self.class.current_user
  11. end
  12. def self.current_user
  13. Thread.current[:current_user]
  14. end
  15. def before_create(model)
  16. # model.created_by = self.current_user
  17. end
  18. def before_update(model)
  19. # model.updated_by = self.current_user
  20. end
  21. end

lib/active_record_extensions/active_record_extensions.rb

0.0% lines covered

23 relevant lines. 0 lines covered and 23 lines missed.
    
  1. class ActiveRecord::Base
  2. def self.validates_path(*args)
  3. configuration = args.extract_options!
  4. validates_each(args, configuration) do |record, attr_name, value|
  5. page = Page.find_by_path(value)
  6. record.errors.add(attr_name, :page_not_found, default: configuration[:message]) if page.nil? || page.is_a?(FileNotFoundPage)
  7. end
  8. end
  9. def self.object_id_attr(symbol, klass)
  10. module_eval %{
  11. def #{symbol}
  12. if @#{symbol}.nil? or (@old_#{symbol}_id != #{symbol}_id)
  13. @old_#{symbol}_id = #{symbol}_id
  14. klass = #{klass}.descendants.find { |d| d.#{symbol}_name == #{symbol}_id }
  15. klass ||= #{klass}
  16. @#{symbol} = klass.new
  17. else
  18. @#{symbol}
  19. end
  20. end
  21. }
  22. end
  23. end

lib/annotatable.rb

0.0% lines covered

57 relevant lines. 0 lines covered and 57 lines missed.
    
  1. module Annotatable
  2. def self.included(base)
  3. base.extend ClassMethods
  4. end
  5. module ClassMethods
  6. def self.extended(base)
  7. base.instance_eval do
  8. alias :inherited_without_annotatable :inherited
  9. alias :inherited :inherited_with_annotatable
  10. end
  11. end
  12. def annotate(*attrs)
  13. options = {}
  14. options = attrs.pop if attrs.last.is_a?(Hash)
  15. options.symbolize_keys!
  16. inherit = options[:inherit]
  17. if inherit
  18. @inherited_annotations ||= []
  19. @inherited_annotations += attrs
  20. end
  21. attrs.each do |attr|
  22. class_eval %{
  23. def self.#{attr}(string = nil)
  24. @#{attr} = string || @#{attr}
  25. end
  26. def #{attr}(string = nil)
  27. self.class.#{attr}(string)
  28. end
  29. def self.#{attr}=(string = nil)
  30. #{attr}(string)
  31. end
  32. def #{attr}=(string = nil)
  33. self.class.#{attr}=(string)
  34. end
  35. }
  36. end
  37. attrs
  38. end
  39. def inherited_with_annotatable(subclass)
  40. inherited_without_annotatable(subclass)
  41. (['inherited_annotations'] + (@inherited_annotations || [])).each do |t|
  42. ivar = "@#{t}"
  43. subclass.instance_variable_set(ivar, instance_variable_get(ivar))
  44. end
  45. end
  46. end
  47. end
  48. # We don't necessarily have ActiveSupport loaded yet!
  49. class Hash
  50. # Return a new hash with all keys converted to symbols.
  51. def symbolize_keys
  52. inject({}) do |options, (key, value)|
  53. options[key.to_sym || key] = value
  54. options
  55. end
  56. end
  57. # Destructively convert all keys to symbols.
  58. def symbolize_keys!
  59. replace(symbolize_keys)
  60. end
  61. end

lib/configuration_extensions/configuration_extensions.rb

0.0% lines covered

177 relevant lines. 0 lines covered and 177 lines missed.
    
  1. module TrustyCms
  2. autoload :Cache, 'rack/cache'
  3. class << self
  4. # Returns the TrustyCms::Config eigenclass object, so it can be used wherever you would use TrustyCms::Config.
  5. #
  6. # TrustyCms.config['site.title']
  7. # TrustyCms.config['site.url'] = 'example.com'
  8. #
  9. # but it will also yield itself to a block:
  10. #
  11. # TrustyCms.config do |config|
  12. # config.define 'something', default => 'something'
  13. # config['other.thing'] = 'nothing'
  14. # end
  15. #
  16. def config # method must be defined before any initializers run
  17. yield TrustyCms::Config if block_given?
  18. TrustyCms::Config
  19. end
  20. # Returns the configuration object with which this application was initialized.
  21. # For now it's exactly the same as calling Rails.configuration except that it will also yield itself to a block.
  22. #
  23. def configuration
  24. yield Rails.configuration if block_given?
  25. Rails.configuration
  26. end
  27. # Returns the root directory of this installation (which is usually the gem directory).
  28. # This is not the same as Rails.root, which is the instance directory and tends to contain only site-delivery material.
  29. #
  30. def root
  31. Pathname.new(TRUSTY_CMS_ROOT) if defined?(TRUSTY_CMS_ROOT)
  32. end
  33. def boot!
  34. unless booted?
  35. preinitialize
  36. pick_boot.run
  37. end
  38. end
  39. def booted?
  40. defined? TrustyCms::Initializer
  41. end
  42. def pick_boot
  43. case
  44. when app?
  45. AppBoot.new
  46. when vendor?
  47. VendorBoot.new
  48. else
  49. GemBoot.new
  50. end
  51. end
  52. def vendor?
  53. File.exist?("#{Rails.root}/vendor/trusty")
  54. end
  55. def app?
  56. File.exist?("#{Rails.root}/lib/trusty_cms.rb")
  57. end
  58. def preinitialize
  59. load(preinitializer_path) if File.exist?(preinitializer_path)
  60. end
  61. def loaded_via_gem?
  62. pick_boot.is_a? GemBoot
  63. end
  64. def preinitializer_path
  65. "#{Rails.root}/config/preinitializer.rb"
  66. end
  67. end
  68. end
  69. class Rails::Application::Configuration
  70. # The TrustyCms::Configuration class extends Rails::Configuration with three purposes:
  71. # * to reset some rails defaults so that files are found in TRUSTY_CMS_ROOT instead of Rails.root
  72. # * to notice that some gems and plugins are in fact trusty extensions
  73. # * to notice that some trusty extensions add load paths (for plugins, controllers, metal, etc)
  74. attr_accessor :extension_paths, :ignored_extensions
  75. def initialize_extension_paths
  76. self.extension_paths = default_extension_paths
  77. self.ignored_extensions = []
  78. end
  79. # Sets the locations in which we look for vendored extensions. Normally:
  80. # Rails.root/vendor/extensions
  81. # TrustyCms.root/vendor/extensions
  82. # There are no vendor/* directories in +TRUSTY_CMS_ROOT+ any more but the possibility remains for compatibility reasons.
  83. # In test mode we also add a fixtures path for testing the extension loader.
  84. #
  85. def default_extension_paths
  86. env = ENV["RAILS_ENV"] || Rails.env
  87. paths = [Rails.root + 'vendor/extensions']
  88. paths.unshift(TRUSTY_CMS_ROOT + "/vendor/extensions") unless Rails.root == TRUSTY_CMS_ROOT
  89. paths.unshift(TRUSTY_CMS_ROOT + "test/fixtures/extensions") if env =~ /test/
  90. paths
  91. end
  92. # The list of extensions, expanded and in load order, that results from combining all the extension
  93. # configuration directives. These are the extensions that will actually be loaded or migrated,
  94. # and for most purposes this is the list you want to refer to.
  95. #
  96. # TrustyCms.configuration.enabled_extensions # => [:name, :name, :name, :name]
  97. #
  98. # Note that an extension enabled is not the same as an extension activated or even loaded: it just means
  99. # that the application is configured to load that extension.
  100. #
  101. def enabled_extensions
  102. @enabled_extensions ||= expanded_extension_list - ignored_extensions
  103. end
  104. # The expanded and ordered list of extensions, including any that may later be ignored. This can be configured
  105. # (it is here that the :all entry is expanded to mean 'everything else'), or will default to an alphabetical list
  106. # of every extension found among gems and vendor/extensions directories.
  107. #
  108. # TrustyCms.configuration.expanded_extension_list # => [:name, :name, :name, :name]
  109. #
  110. # If an extension in the configurted list is not found, a LoadError will be thrown from here.
  111. #
  112. def expanded_extension_list
  113. # NB. it should remain possible to say config.extensions = []
  114. @extension_list ||= extensions ? expand_and_check(extensions) : available_extensions
  115. end
  116. def expand_and_check(extension_list)
  117. #:nodoc
  118. missing_extensions = extension_list - [:all] - available_extensions
  119. raise LoadError, "These configured extensions have not been found: #{missing_extensions.to_sentence}" if missing_extensions.any?
  120. if m = extension_list.index(:all)
  121. extension_list[m] = available_extensions - extension_list
  122. end
  123. extension_list.flatten
  124. end
  125. # Returns the checked and expanded list of extensions-to-enable. This may be derived from a list passed to
  126. # +config.extensions=+ or it may have defaulted to all available extensions.
  127. # Without such a call, we default to the alphabetical list of all well-formed vendor and gem extensions
  128. # returned by +available_extensions+.
  129. #
  130. # TrustyCms.configuration.extensions # => [:name, :all, :name]
  131. #
  132. def extensions
  133. @requested_extensions ||= available_extensions
  134. end
  135. # Sets the list of extensions that will be loaded and the order in which to load them.
  136. # It can include an :all marker to mean 'everything else' and is typically set in environment.rb:
  137. # config.extensions = [:layouts, :taggable, :all]
  138. # config.extensions = [:dashboard, :blog, :all]
  139. # config.extensions = [:dashboard, :blog, :all, :comments]
  140. #
  141. # A LoadError is raised if any of the specified extensions can't be found.
  142. #
  143. def extensions=(extensions)
  144. @requested_extensions = extensions
  145. end
  146. # This is a configurable list of extension that should not be loaded.
  147. # config.ignore_extensions = [:experimental, :broken]
  148. # You can also retrieve the list with +ignored_extensions+:
  149. # TrustyCms.configuration.ignored_extensions # => [:experimental, :broken]
  150. # These exclusions are applied regardless of dependencies and extension locations. A configuration that bundles
  151. # required extensions then ignores them will not boot and is likely to fail with errors about unitialized constants.
  152. #
  153. def ignore_extensions(array)
  154. self.ignored_extensions |= array
  155. end
  156. # Returns an alphabetical list of every extension found among all the load paths and bundled gems. Any plugin or
  157. # gem whose path ends in the form +trusty-something-extension+ is considered to be an extension.
  158. #
  159. # TrustyCms.configuration.available_extensions # => [:name, :name, :name, :name]
  160. #
  161. # This method is always called during initialization, either as a default or to check that specified extensions are
  162. # available. One of its side effects is to populate the ExtensionLoader's list of extension root locations, later
  163. # used when activating those extensions that have been enabled.
  164. #
  165. def available_extensions
  166. @available_extensions ||= (vendored_extensions + gem_extensions).uniq.sort.map(&:to_sym)
  167. end
  168. # Searches the defined extension_paths for subdirectories and returns a list of names as symbols.
  169. #
  170. # TrustyCms.configuration.vendored_extensions # => [:name, :name]
  171. #
  172. def vendored_extensions
  173. extension_paths.each_with_object([]) do |load_path, found|
  174. Dir["#{load_path}/*"].each do |path|
  175. if File.directory?(path)
  176. ep = TrustyCms::ExtensionLoader.record_path(path)
  177. found << ep.name
  178. end
  179. end
  180. end
  181. end
  182. # Scans the bundled gems for any whose name match the +trusty-something-extension+ format
  183. # and returns a list of their names as symbols.
  184. #
  185. # TrustyCms.configuration.gem_extensions # => [:name, :name]
  186. #
  187. def gem_extensions
  188. Gem.loaded_specs.each_with_object([]) do |(gemname, gemspec), found|
  189. if gemname =~ /trusty-.*-extension$/
  190. ep = TrustyCms::ExtensionLoader.record_path(gemspec.full_gem_path, gemname)
  191. found << ep.name
  192. end
  193. end
  194. end
  195. # Old extension-dependency mechanism now deprecated
  196. #
  197. def extension(ext)
  198. ::ActiveSupport::Deprecation.warn("Extension dependencies have been deprecated and are no longer supported in trusty 1.0. Extensions with dependencies should be packaged as gems and use the .gemspec to declare them.", caller)
  199. end
  200. # Old gem-invogation method now deprecated
  201. #
  202. def gem(name, options = {})
  203. ::ActiveSupport::Deprecation.warn("Please declare gem dependencies in your Gemfile (or for an extension, in the .gemspec file).", caller)
  204. super
  205. end
  206. # Returns the AdminUI singleton, giving get-and-set access to the tabs and partial-sets it defines.
  207. # More commonly accessed in the initializer via its call to +configuration.admin+.
  208. #
  209. def admin
  210. TrustyCms::AdminUI.instance
  211. end
  212. private
  213. # Overrides the Rails::Initializer default to add plugin paths in TRUSTY_CMS_ROOT as well as Rails.root.
  214. #
  215. def default_plugin_paths
  216. super + ["#{TRUSTY_CMS_ROOT}/lib/plugins", "#{TRUSTY_CMS_ROOT}/vendor/plugins"]
  217. end
  218. # Overrides the Rails::Initializer default to look for views in TRUSTY_CMS_ROOT rather than Rails.root.
  219. #
  220. def default_view_path
  221. File.join(TRUSTY_CMS_ROOT, 'app', 'views')
  222. end
  223. # Overrides the Rails::Initializer default to look for controllers in TRUSTY_CMS_ROOT rather than Rails.root.
  224. #
  225. def default_controller_paths
  226. [File.join(TRUSTY_CMS_ROOT, 'app', 'controllers')]
  227. end
  228. end
  229. class Boot
  230. def run
  231. load_mutex
  232. load_initializer
  233. end
  234. # RubyGems from version 1.6 does not require thread but Rails depend on it
  235. # This should newer rails do automaticly
  236. def load_mutex
  237. begin
  238. require "thread" unless defined?(Mutex)
  239. rescue LoadError => _
  240. $stderr.puts %(Mutex could not be initialized. #{load_error_message})
  241. exit 1
  242. end
  243. end
  244. def load_initializer
  245. begin
  246. require 'trusty_cms'
  247. require 'trusty_cms/initializer'
  248. rescue LoadError => _
  249. $stderr.puts %(TrustyCms could not be initialized. #{load_error_message})
  250. exit 1
  251. end
  252. TrustyCms::Initializer.run(:set_load_path)
  253. TrustyCms::Initializer.run(:install_gem_spec_stubs)
  254. Rails::GemDependency.add_frozen_gem_path
  255. end
  256. end
  257. class VendorBoot < Boot
  258. def load_initializer
  259. $LOAD_PATH.unshift "#{Rails.root}/vendor/trusty_cms/lib"
  260. super
  261. end
  262. def load_error_message
  263. "Please verify that vendor/trusty contains a complete copy of the TrustyCms sources."
  264. end
  265. end
  266. class AppBoot < Boot
  267. def load_initializer
  268. $LOAD_PATH.unshift "#{Rails.root}/lib"
  269. super
  270. end
  271. def load_error_message
  272. "Please verify that you have a complete copy of the TrustyCms sources."
  273. end
  274. end
  275. class GemBoot < Boot
  276. # The location and version of the trusty gem should be set in your Gemfile
  277. def load_error_message
  278. "Have you run `bundle install`?'."
  279. end
  280. end

lib/generators/extension/extension_generator.rb

0.0% lines covered

82 relevant lines. 0 lines covered and 82 lines missed.
    
  1. begin
  2. require 'git'
  3. rescue LoadError
  4. end
  5. class ExtensionGenerator < Rails::Generator::NamedBase
  6. default_options :with_test_unit => false
  7. attr_reader :extension_path, :extension_file_name
  8. def initialize(runtime_args, runtime_options = {})
  9. super
  10. @extension_file_name = "#{file_name}_extension"
  11. @extension_path = "vendor/extensions/#{file_name}"
  12. end
  13. def manifest
  14. record do |m|
  15. m.directory "#{extension_path}/app/controllers"
  16. m.directory "#{extension_path}/app/helpers"
  17. m.directory "#{extension_path}/app/models"
  18. m.directory "#{extension_path}/app/views"
  19. m.directory "#{extension_path}/config/locales"
  20. m.directory "#{extension_path}/config/initializers"
  21. m.directory "#{extension_path}/db/migrate"
  22. m.directory "#{extension_path}/lib/tasks"
  23. m.template 'README.md', "#{extension_path}/README.md"
  24. m.template 'extension.rb', "#{extension_path}/#{extension_file_name}.rb"
  25. m.template 'tasks.rake', "#{extension_path}/lib/tasks/#{extension_file_name}_tasks.rake"
  26. m.template 'en.yml', "#{extension_path}/config/locales/en.yml"
  27. m.template 'routes.rb', "#{extension_path}/config/routes.rb"
  28. m.template 'radiant_config.rb', "#{extension_path}/config/initializers/radiant_config.rb"
  29. m.template 'lib.rb', "#{extension_path}/lib/radiant-#{file_name}-extension.rb"
  30. m.template 'gemspec.rb', "#{extension_path}/radiant-#{file_name}-extension.gemspec"
  31. if options[:with_test_unit]
  32. m.directory "#{extension_path}/test/fixtures"
  33. m.directory "#{extension_path}/test/functional"
  34. m.directory "#{extension_path}/test/unit"
  35. m.template 'Rakefile', "#{extension_path}/Rakefile"
  36. m.template 'test_helper.rb', "#{extension_path}/test/test_helper.rb"
  37. m.template 'functional_test.rb', "#{extension_path}/test/functional/#{extension_file_name}_test.rb"
  38. else
  39. m.directory "#{extension_path}/spec/controllers"
  40. m.directory "#{extension_path}/spec/models"
  41. m.directory "#{extension_path}/spec/views"
  42. m.directory "#{extension_path}/spec/helpers"
  43. m.directory "#{extension_path}/features/support"
  44. m.directory "#{extension_path}/features/step_definitions/admin"
  45. m.template 'RSpecRakefile', "#{extension_path}/Rakefile"
  46. m.template 'spec_helper.rb', "#{extension_path}/spec/spec_helper.rb"
  47. m.file 'spec.opts', "#{extension_path}/spec/spec.opts"
  48. m.file 'cucumber.yml', "#{extension_path}/cucumber.yml"
  49. m.template 'cucumber_env.rb', "#{extension_path}/features/support/env.rb"
  50. m.template 'cucumber_paths.rb', "#{extension_path}/features/support/paths.rb"
  51. end
  52. end
  53. end
  54. def class_name
  55. super.to_name.gsub(' ', '') + 'Extension'
  56. end
  57. def extension_name
  58. class_name.to_name('Extension')
  59. end
  60. def author_info
  61. @author_info ||= begin
  62. Git.global_config
  63. rescue NameError
  64. {}
  65. end
  66. end
  67. def homepage
  68. author_info['github.user'] ? "http://github.com/#{author_info['github.user']}/radiant-#{file_name}-extension" : "http://example.com/#{file_name}"
  69. end
  70. def author_email
  71. author_info['user.email'] || 'your email'
  72. end
  73. def author_name
  74. author_info['user.name'] || 'Your Name'
  75. end
  76. def add_options!(opt)
  77. opt.separator ''
  78. opt.separator 'Options:'
  79. opt.on("--with-test-unit",
  80. "Use Test::Unit for this extension instead of RSpec") { |v| options[:with_test_unit] = v }
  81. end
  82. end

lib/generators/extension/templates/cucumber_env.rb

0.0% lines covered

7 relevant lines. 0 lines covered and 7 lines missed.
    
  1. # Sets up the Rails environment for Cucumber
  2. ENV["Rails.env"] = "test"
  3. # Extension root
  4. extension_env = File.expand_path(File.dirname(__FILE__) + '/../../../../../config/environment')
  5. require extension_env+'.rb'
  6. Dir.glob(File.join(TRUSTY_CMS_ROOT, "features", "**", "*.rb")).each {|step| require step unless step =~ /datasets_loader\.rb$/}
  7. Cucumber::Rails::World.class_eval do
  8. dataset :<%= file_name %>
  9. end

lib/generators/extension/templates/cucumber_paths.rb

0.0% lines covered

6 relevant lines. 0 lines covered and 6 lines missed.
    
  1. module NavigationHelpers
  2. # Extend the standard PathMatchers with your own paths
  3. # to be used in your features.
  4. #
  5. # The keys and values here may be used in your standard web steps
  6. # Using:
  7. #
  8. # When I go to the "<%= file_name %>" admin page
  9. #
  10. # would direct the request to the path you provide in the value:
  11. #
  12. # admin_<%= file_name %>_path
  13. #
  14. PathMatchers = {} unless defined?(PathMatchers)
  15. PathMatchers.merge!({
  16. # /<%= file_name %>/i => 'admin_<%= file_name %>_path'
  17. })
  18. end
  19. World(NavigationHelpers)

lib/generators/extension/templates/extension.rb

0.0% lines covered

10 relevant lines. 0 lines covered and 10 lines missed.
    
  1. # Uncomment this if you reference any of your controllers in activate
  2. require "radiant-<%= file_name %>-extension"
  3. class <%= class_name %> < TrustyCms::Extension
  4. version TrustyCms<%= class_name %>::VERSION
  5. description TrustyCms<%= class_name %>::DESCRIPTION
  6. url TrustyCms<%= class_name %>::URL
  7. # See your config/routes.rb file in this extension to define custom routes
  8. extension_config do |config|
  9. # config is the TrustyCms.configuration object
  10. end
  11. def activate
  12. # tab 'Content' do
  13. # add_item "<%= extension_name %>", "/admin/<%= file_name %>", :after => "Pages"
  14. # end
  15. end
  16. end

lib/generators/extension/templates/functional_test.rb

0.0% lines covered

10 relevant lines. 0 lines covered and 10 lines missed.
    
  1. require File.dirname(__FILE__) + '/../test_helper'
  2. class <%= class_name %>Test < Test::Unit::TestCase
  3. # Replace this with your real tests.
  4. def test_this_extension
  5. flunk
  6. end
  7. def test_initialization
  8. assert_equal File.join(File.expand_path(Rails.root), 'vendor', 'extensions', '<%= file_name %>'), <%= class_name %>.root
  9. assert_equal '<%= extension_name %>', <%= class_name %>.extension_name
  10. end
  11. end

lib/generators/extension/templates/gemspec.rb

0.0% lines covered

20 relevant lines. 0 lines covered and 20 lines missed.
    
  1. # -*- encoding: utf-8 -*-
  2. $:.push File.expand_path("../lib", __FILE__)
  3. require "radiant-<%= file_name %>-extension"
  4. Gem::Specification.new do |s|
  5. s.name = "radiant-<%= file_name %>-extension"
  6. s.version = TrustyCms<%= class_name %>::VERSION
  7. s.platform = Gem::Platform::RUBY
  8. s.authors = TrustyCms<%= class_name %>::AUTHORS
  9. s.email = TrustyCms<%= class_name %>::EMAIL
  10. s.homepage = TrustyCms<%= class_name %>::URL
  11. s.summary = TrustyCms<%= class_name %>::SUMMARY
  12. s.description = TrustyCms<%= class_name %>::DESCRIPTION
  13. # Define gem dependencies here.
  14. # Don't include a dependency on radiant itself: it causes problems when radiant is in vendor/radiant.
  15. # s.add_dependency "something", "~> 1.0.0"
  16. # s.add_dependency "radiant-some-extension", "~> 1.0.0"
  17. ignores = if File.exist?('.gitignore')
  18. File.read('.gitignore').split("\n").inject([]) {|a,p| a + Dir[p] }
  19. else
  20. []
  21. end
  22. s.files = Dir['**/*'] - ignores
  23. s.test_files = Dir['test/**/*','spec/**/*','features/**/*'] - ignores
  24. # s.executables = Dir['bin/*'] - ignores
  25. s.require_paths = ["lib"]
  26. end

lib/generators/extension/templates/lib.rb

0.0% lines covered

8 relevant lines. 0 lines covered and 8 lines missed.
    
  1. module TrustyCms<%= class_name %>
  2. VERSION = "1.0.0"
  3. SUMMARY = "<%= extension_name %> for TrustyCms CMS"
  4. DESCRIPTION = "Makes TrustyCms better by adding <%= file_name %>!"
  5. URL = "<%= homepage %>"
  6. AUTHORS = ["<%= author_name %>"]
  7. EMAIL = ["<%= author_email %>"]
  8. end

lib/generators/extension/templates/migration.rb

0.0% lines covered

6 relevant lines. 0 lines covered and 6 lines missed.
    
  1. class Create<%= class_name %>Schema < ActiveRecord::Migration[5.2]
  2. def self.up
  3. end
  4. def self.down
  5. end
  6. end

lib/generators/extension/templates/radiant_config.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. TrustyCms.config do |config|
  2. # config.define "setting.name", :default => 'value', :select_from => ['foo', 'bar']
  3. end

lib/generators/extension/templates/routes.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. ActionController::Routing::Routes.draw do |map|
  2. # map.namespace :admin, :member => { :remove => :get } do |admin|
  3. # admin.resources :<%= file_name %>
  4. # end
  5. end

lib/generators/extension/templates/spec_helper.rb

0.0% lines covered

23 relevant lines. 0 lines covered and 23 lines missed.
    
  1. unless defined? TRUSTY_CMS_ROOT
  2. ENV["Rails.env"] = "test"
  3. case
  4. when ENV.fetch('RADIANT_ENV_FILE')
  5. require ENV.fetch('RADIANT_ENV_FILE')
  6. when File.dirname(__FILE__) =~ %r{vendor/trusty_cms/vendor/extensions}
  7. require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
  8. else
  9. require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
  10. end
  11. end
  12. require "#{TRUSTY_CMS_ROOT}/spec/spec_helper"
  13. Dataset::Resolver.default << (File.dirname(__FILE__) + "/datasets")
  14. # Include any datasets from loaded extensions
  15. TrustyCms::Extension.descendants.each do |extension|
  16. if File.directory?(extension.root + "/spec/datasets")
  17. Dataset::Resolver.default << (extension.root + "/spec/datasets")
  18. end
  19. end
  20. if File.directory?(File.dirname(__FILE__) + "/matchers")
  21. Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
  22. end
  23. Spec::Runner.configure do |config|
  24. # config.use_transactional_fixtures = true
  25. # config.use_instantiated_fixtures = false
  26. # config.fixture_path = Rails.root + '/spec/fixtures'
  27. # You can declare fixtures for each behaviour like this:
  28. # describe "...." do
  29. # fixtures :table_a, :table_b
  30. #
  31. # Alternatively, if you prefer to declare them only once, you can
  32. # do so here, like so ...
  33. #
  34. # config.global_fixtures = :table_a, :table_b
  35. #
  36. # If you declare global fixtures, be aware that they will be declared
  37. # for all of your examples, even those that don't use them.
  38. end

lib/generators/extension/templates/test_helper.rb

0.0% lines covered

17 relevant lines. 0 lines covered and 17 lines missed.
    
  1. require 'test/unit'
  2. # Load the environment
  3. unless defined? TRUSTY_CMS_ROOT
  4. ENV['Rails.env'] = 'test'
  5. case
  6. when ENV.fetch('RADIANT_ENV_FILE')
  7. require ENV.fetch('RADIANT_ENV_FILE')
  8. when File.dirname(__FILE__) =~ %r{vendor/trusty_cms/vendor/extensions}
  9. require "#{File.expand_path(File.dirname(__FILE__) + '/../../../../../../')}/config/environment"
  10. else
  11. require "#{File.expand_path(File.dirname(__FILE__) + '/../../../../')}/config/environment"
  12. end
  13. end
  14. require "#{TRUSTY_CMS_ROOT}/test/test_helper"
  15. class ActiveSupport::TestCase
  16. # Include a helper to make testing Radius tags easier
  17. test_helper :extension_tags
  18. # Add the fixture directory to the fixture path
  19. self.fixture_path << File.dirname(__FILE__) + '/fixtures'
  20. # Add more helper methods to be used by all extension tests here...
  21. end

lib/generators/extension_controller/extension_controller_generator.rb

0.0% lines covered

64 relevant lines. 0 lines covered and 64 lines missed.
    
  1. require 'rails_generator/base'
  2. require 'rails_generator/generators/components/controller/controller_generator'
  3. class ExtensionControllerGenerator < ControllerGenerator
  4. attr_accessor :extension_name
  5. default_options :with_test_unit => false
  6. def initialize(runtime_args, runtime_options = {})
  7. runtime_args = runtime_args.dup
  8. @extension_name = runtime_args.shift
  9. super(runtime_args, runtime_options)
  10. end
  11. def manifest
  12. if extension_uses_rspec?
  13. rspec_manifest
  14. else
  15. super
  16. end
  17. end
  18. def rspec_manifest
  19. record do |m|
  20. # Check for class naming collisions.
  21. m.class_collisions class_path, "#{class_name}Controller", "#{class_name}Helper"
  22. # Controller, helper, views, and spec directories.
  23. m.directory File.join('app/controllers', class_path)
  24. m.directory File.join('app/helpers', class_path)
  25. m.directory File.join('app/views', class_path, file_name)
  26. m.directory File.join('spec/controllers', class_path)
  27. m.directory File.join('spec/helpers', class_path)
  28. m.directory File.join('spec/views', class_path, file_name)
  29. # Controller spec, class, and helper.
  30. m.template 'controller_spec.rb',
  31. File.join('spec/controllers', class_path, "#{file_name}_controller_spec.rb")
  32. m.template 'helper_spec.rb',
  33. File.join('spec/helpers', class_path, "#{file_name}_helper_spec.rb")
  34. m.template 'controller:controller.rb',
  35. File.join('app/controllers', class_path, "#{file_name}_controller.rb")
  36. m.template 'controller:helper.rb',
  37. File.join('app/helpers', class_path, "#{file_name}_helper.rb")
  38. # Spec and view template for each action.
  39. actions.each do |action|
  40. m.template 'view_spec.rb',
  41. File.join('spec/views', class_path, file_name, "#{action}_view_spec.rb"),
  42. :assigns => { :action => action, :model => file_name }
  43. path = File.join('app/views', class_path, file_name, "#{action}.html.erb")
  44. m.template 'controller:view.html.erb',
  45. path,
  46. :assigns => { :action => action, :path => path }
  47. end
  48. end
  49. end
  50. def banner
  51. "Usage: #{$0} #{spec.name} ExtensionName #{spec.name.camelize}Name [options]"
  52. end
  53. def extension_path
  54. File.join('vendor', 'extensions', @extension_name.underscore)
  55. end
  56. def destination_root
  57. File.join(Rails.root, extension_path)
  58. end
  59. def extension_uses_rspec?
  60. File.exist?(File.join(destination_root, 'spec')) && !options[:with_test_unit]
  61. end
  62. def add_options!(opt)
  63. opt.separator ''
  64. opt.separator 'Options:'
  65. opt.on("--with-test-unit",
  66. "Use Test::Unit tests instead sof RSpec.") { |v| options[:with_test_unit] = v }
  67. end
  68. end

lib/generators/extension_controller/templates/controller.rb

0.0% lines covered

6 relevant lines. 0 lines covered and 6 lines missed.
    
  1. class <%= class_name %>Controller < ApplicationController
  2. # Remove this line if your controller should only be accessible to users
  3. # that are logged in:
  4. # no_login_required
  5. <% for action in actions -%>
  6. def <%= action %>
  7. end
  8. <% end -%>
  9. end

lib/generators/extension_controller/templates/controller_spec.rb

0.0% lines covered

17 relevant lines. 0 lines covered and 17 lines missed.
    
  1. require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper'
  2. describe <%= class_name %>Controller do
  3. <% if actions.empty? -%>
  4. #Delete this example and add some real ones
  5. <% else -%>
  6. #Delete these examples and add some real ones
  7. <% end -%>
  8. it "should use <%= class_name %>Controller" do
  9. controller.should be_an_instance_of(<%= class_name %>Controller)
  10. end
  11. <% unless actions.empty? -%>
  12. <% for action in actions -%>
  13. it "GET '<%= action %>' should be successful" do
  14. get '<%= action %>'
  15. response.should be_success
  16. end
  17. <% end -%>
  18. <% end -%>
  19. end

lib/generators/extension_controller/templates/functional_test.rb

0.0% lines covered

7 relevant lines. 0 lines covered and 7 lines missed.
    
  1. require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
  2. # Re-raise errors caught by the controller.
  3. <%= class_name %>Controller.class_eval { def rescue_action(e) raise e end }
  4. class <%= class_name %>ControllerTest < ActionController::TestCase
  5. # Replace this with your real tests.
  6. def test_truth
  7. assert true
  8. end
  9. end

lib/generators/extension_controller/templates/helper.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. module <%= class_name %>Helper
  2. end

lib/generators/extension_controller/templates/helper_spec.rb

0.0% lines covered

7 relevant lines. 0 lines covered and 7 lines missed.
    
  1. require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper'
  2. describe <%= class_name %>Helper do
  3. #Delete this example and add some real ones or delete this file
  4. it "should include the <%= class_name %>Helper" do
  5. included_modules = self.metaclass.send :included_modules
  6. included_modules.should include(<%= class_name %>Helper)
  7. end
  8. end

lib/generators/extension_controller/templates/helper_test.rb

0.0% lines covered

3 relevant lines. 0 lines covered and 3 lines missed.
    
  1. require 'test_helper'
  2. class <%= class_name %>HelperTest < ActionView::TestCase
  3. end

lib/generators/extension_controller/templates/view_spec.rb

0.0% lines covered

9 relevant lines. 0 lines covered and 9 lines missed.
    
  1. require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../../spec_helper'
  2. describe "/<%= class_name.underscore %>/<%= action %>" do
  3. before do
  4. render '<%= class_name.underscore %>/<%= action %>'
  5. end
  6. # Delete this example and add some real ones or delete this file
  7. it "should tell you where to find the file" do
  8. response.should have_tag('p', 'Find me in app/views/<%= class_name.underscore %>/<%= action %>.rhtml')
  9. end
  10. end

lib/generators/extension_mailer/extension_mailer_generator.rb

0.0% lines covered

50 relevant lines. 0 lines covered and 50 lines missed.
    
  1. require 'rails_generator/base'
  2. require 'rails_generator/generators/components/mailer/mailer_generator'
  3. class ExtensionMailerGenerator < MailerGenerator
  4. attr_accessor :extension_name
  5. default_options :with_test_unit => false
  6. def initialize(runtime_args, runtime_options = {})
  7. runtime_args = runtime_args.dup
  8. @extension_name = runtime_args.shift
  9. super(runtime_args, runtime_options)
  10. end
  11. def manifest
  12. if extension_uses_rspec?
  13. rspec_manifest
  14. else
  15. super
  16. end
  17. end
  18. def rspec_manifest
  19. record do |m|
  20. # Check for class naming collisions.
  21. m.class_collisions class_path, class_name
  22. # Mailer, view, test, and fixture directories.
  23. m.directory File.join('app/models', class_path)
  24. m.directory File.join('app/views', file_path)
  25. # Mailer class and unit test.
  26. m.template "mailer:mailer.rb", File.join('app/models', class_path, "#{file_name}.rb")
  27. # View template and fixture for each action.
  28. actions.each do |action|
  29. relative_path = File.join(file_path, action)
  30. view_path = File.join('app/views', "#{relative_path}.erb")
  31. m.template "mailer:view.erb", view_path,
  32. :assigns => { :action => action, :path => view_path }
  33. end
  34. end
  35. end
  36. def banner
  37. "Usage: #{$0} #{spec.name} ExtensionName #{spec.name.camelize}Name [options]"
  38. end
  39. def extension_path
  40. File.join('vendor', 'extensions', @extension_name.underscore)
  41. end
  42. def destination_root
  43. File.join(Rails.root, extension_path)
  44. end
  45. def extension_uses_rspec?
  46. File.exist?(File.join(destination_root, 'spec')) && !options[:with_test_unit]
  47. end
  48. def add_options!(opt)
  49. opt.separator ''
  50. opt.separator 'Options:'
  51. opt.on("--with-test-unit",
  52. "Use Test::Unit tests instead sof RSpec.") { |v| options[:with_test_unit] = v }
  53. end
  54. end

lib/generators/extension_mailer/templates/mailer.rb

0.0% lines covered

11 relevant lines. 0 lines covered and 11 lines missed.
    
  1. class <%= class_name %> < ActionMailer::Base
  2. <% for action in actions -%>
  3. def <%= action %>(sent_at = Time.now)
  4. subject '<%= class_name %>#<%= action %>'
  5. recipients ''
  6. from ''
  7. sent_on sent_at
  8. body :greeting => 'Hi,'
  9. end
  10. <% end -%>
  11. end

lib/generators/extension_mailer/templates/unit_test.rb

0.0% lines covered

17 relevant lines. 0 lines covered and 17 lines missed.
    
  1. require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
  2. class <%= class_name %>Test < ActionMailer::TestCase
  3. tests <%= class_name %>
  4. <% for action in actions -%>
  5. def test_<%= action %>
  6. @expected.subject = '<%= class_name %>#<%= action %>'
  7. @expected.body = read_fixture('<%= action %>')
  8. @expected.date = Time.now
  9. assert_equal @expected.encoded, <%= class_name %>.create_<%= action %>(@expected.date).encoded
  10. end
  11. <% end -%>
  12. <% if actions.blank? -%>
  13. # replace this with your real tests
  14. def test_truth
  15. assert true
  16. end
  17. <% end -%>
  18. end

lib/generators/extension_migration/extension_migration_generator.rb

0.0% lines covered

19 relevant lines. 0 lines covered and 19 lines missed.
    
  1. require 'rails_generator/base'
  2. require 'rails_generator/generators/components/migration/migration_generator'
  3. class ExtensionMigrationGenerator < MigrationGenerator
  4. attr_accessor :extension_name
  5. def initialize(runtime_args, runtime_options = {})
  6. runtime_args = runtime_args.dup
  7. @extension_name = runtime_args.shift
  8. super(runtime_args, runtime_options)
  9. end
  10. def banner
  11. "Usage: #{$0} extension_migration ExtensionName MigrationName [field:type, field:type]"
  12. end
  13. def extension_path
  14. File.join('vendor', 'extensions', @extension_name.underscore)
  15. end
  16. def destination_root
  17. File.join(Rails.root, extension_path)
  18. end
  19. end

lib/generators/extension_migration/templates/migration.rb

0.0% lines covered

10 relevant lines. 0 lines covered and 10 lines missed.
    
  1. class <%= class_name.underscore.camelize %> < ActiveRecord::Migration[5.2]
  2. def self.up<% attributes.each do |attribute| %>
  3. <%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end -%>
  4. <%- end %>
  5. end
  6. def self.down<% attributes.reverse.each do |attribute| %>
  7. <%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end -%>
  8. <%- end %>
  9. end
  10. end

lib/generators/extension_model/extension_model_generator.rb

0.0% lines covered

50 relevant lines. 0 lines covered and 50 lines missed.
    
  1. require 'rails_generator/base'
  2. require 'rails_generator/generators/components/model/model_generator'
  3. class ExtensionModelGenerator < ModelGenerator
  4. attr_accessor :extension_name
  5. default_options :with_test_unit => false
  6. def initialize(runtime_args, runtime_options = {})
  7. runtime_args = runtime_args.dup
  8. @extension_name = runtime_args.shift
  9. super(runtime_args, runtime_options)
  10. end
  11. def manifest
  12. if extension_uses_rspec?
  13. rspec_manifest
  14. else
  15. super
  16. end
  17. end
  18. def rspec_manifest
  19. record do |m|
  20. # Check for class naming collisions.
  21. m.class_collisions class_path, class_name
  22. # Model, spec, and fixture directories.
  23. m.directory File.join('app/models', class_path)
  24. m.directory File.join('spec/models', class_path)
  25. # m.directory File.join('spec/fixtures', class_path)
  26. # Model class, spec and fixtures.
  27. m.template 'model:model.rb', File.join('app/models', class_path, "#{file_name}.rb")
  28. # m.template 'model:fixtures.yml', File.join('spec/fixtures', class_path, "#{table_name}.yml")
  29. m.template 'model_spec.rb', File.join('spec/models', class_path, "#{file_name}_spec.rb")
  30. unless options[:skip_migration]
  31. m.migration_template 'model:migration.rb', 'db/migrate', :assigns => {
  32. :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
  33. }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
  34. end
  35. end
  36. end
  37. def banner
  38. "Usage: #{$0} extension_model ExtensionName ModelName [field:type, field:type]"
  39. end
  40. def extension_path
  41. File.join('vendor', 'extensions', @extension_name.underscore)
  42. end
  43. def destination_root
  44. File.join(Rails.root, extension_path)
  45. end
  46. def extension_uses_rspec?
  47. File.exist?(File.join(destination_root, 'spec')) && !options[:with_test_unit]
  48. end
  49. def add_options!(opt)
  50. opt.separator ''
  51. opt.separator 'Options:'
  52. opt.on("--with-test-unit",
  53. "Use Test::Unit tests instead sof RSpec.") { |v| options[:with_test_unit] = v }
  54. end
  55. end

lib/generators/extension_model/templates/migration.rb

0.0% lines covered

15 relevant lines. 0 lines covered and 15 lines missed.
    
  1. class <%= migration_name %> < ActiveRecord::Migration[5.2]
  2. def self.up
  3. create_table :<%= table_name %> do |t|
  4. <% for attribute in attributes -%>
  5. t.<%= attribute.type %> :<%= attribute.name %>
  6. <% end -%>
  7. <% unless options[:skip_timestamps] %>
  8. t.timestamps
  9. <% end -%>
  10. end
  11. end
  12. def self.down
  13. drop_table :<%= table_name %>
  14. end
  15. end

lib/generators/extension_model/templates/model.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. class <%= class_name %> < ActiveRecord::Base
  2. end

lib/generators/extension_model/templates/model_spec.rb

0.0% lines covered

9 relevant lines. 0 lines covered and 9 lines missed.
    
  1. require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../spec_helper'
  2. describe <%= class_name %> do
  3. before(:each) do
  4. @<%= file_name %> = <%= class_name %>.new
  5. end
  6. it "should be valid" do
  7. @<%= file_name %>.should be_valid
  8. end
  9. end

lib/generators/extension_model/templates/unit_test.rb

0.0% lines covered

6 relevant lines. 0 lines covered and 6 lines missed.
    
  1. require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
  2. class <%= class_name %>Test < ActiveSupport::TestCase
  3. # Replace this with your real tests.
  4. def test_truth
  5. assert true
  6. end
  7. end

lib/generators/generator_base_extension.rb

0.0% lines covered

15 relevant lines. 0 lines covered and 15 lines missed.
    
  1. require 'rails_generator'
  2. module TrustyCms
  3. module GeneratorBaseExtension
  4. def self.included(base)
  5. base.class_eval {
  6. alias_method :existing_migrations_without_extensions, :existing_migrations
  7. alias_method :existing_migrations, :existing_migrations_with_extensions
  8. }
  9. end
  10. def existing_migrations_with_extensions(file_name)
  11. Dir.glob("#{destination_path(@migration_directory)}/[0-9]*_*.rb").grep(/[0-9]+_#{file_name}.rb$/)
  12. end
  13. end
  14. end
  15. Rails::Generator::Commands::Base.class_eval { include TrustyCms::GeneratorBaseExtension }

lib/generators/instance/instance_generator.rb

0.0% lines covered

112 relevant lines. 0 lines covered and 112 lines missed.
    
  1. require 'rbconfig'
  2. # Small addition to enable the enqueing of "bundle install"
  3. class Rails::Generator::Commands::Create
  4. def run_bundler(destination_root)
  5. # thanks to http://spectator.in/2011/01/28/bundler-in-subshells/
  6. bundler_vars = %w(BUNDLE_GEMFILE RUBYOPT )
  7. command = %{"#{Gem.ruby}" -rubygems "#{Gem.bin_path('bundler', 'bundle')}" install --gemfile="#{File.join(File.expand_path(destination_root), 'Gemfile')}"}
  8. begin
  9. bundled_env = ENV.to_hash
  10. bundler_vars.each{ |var| ENV.delete(var) }
  11. print `#{command}`
  12. ensure
  13. ENV.replace(bundled_env)
  14. end
  15. end
  16. end
  17. class InstanceGenerator < Rails::Generator::Base
  18. DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
  19. Config::CONFIG['ruby_install_name'])
  20. DATABASES = %w( mysql postgresql sqlite3 sqlserver db2 )
  21. MYSQL_SOCKET_LOCATIONS = [
  22. "/tmp/mysql.sock", # default
  23. "/var/run/mysqld/mysqld.sock", # debian/gentoo
  24. "/var/tmp/mysql.sock", # freebsd
  25. "/var/lib/mysql/mysql.sock", # fedora
  26. "/opt/local/lib/mysql/mysql.sock", # fedora
  27. "/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
  28. "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
  29. "/opt/local/var/run/mysql5/mysqld.sock" # mac + darwinports + mysql5
  30. ]
  31. default_options :db => "sqlite3", :shebang => DEFAULT_SHEBANG, :freeze => false
  32. def initialize(runtime_args, runtime_options = {})
  33. super
  34. usage if args.empty?
  35. usage("Databases supported for preconfiguration are: #{DATABASES.join(", ")}") if (options[:db] && !DATABASES.include?(options[:db]))
  36. @destination_root = args.shift
  37. end
  38. def manifest
  39. # The absolute location of the TrustyCms files
  40. root = File.expand_path(TRUSTY_CMS_ROOT)
  41. # Use /usr/bin/env if no special shebang was specified
  42. script_options = { :chmod => 0755, :shebang => options[:shebang] == DEFAULT_SHEBANG ? nil : options[:shebang] }
  43. dispatcher_options = { :chmod => 0755, :shebang => options[:shebang] }
  44. record do |m|
  45. # Root directory
  46. m.directory ""
  47. # Standard files and directories
  48. base_dirs = %w(config config/environments config/initializers db log script public vendor/plugins vendor/extensions)
  49. text_files = %w(CHANGELOG.md CONTRIBUTORS.md LICENSE.md INSTALL.md README.md)
  50. environments = Dir["#{root}/config/environments/*.rb"]
  51. bundler_compatibility_files = %w{config/preinitializer.rb}
  52. schema_file = %w{db/schema.rb}
  53. scripts = Dir["#{root}/script/**/*"].reject { |f| f =~ /(destroy|generate|plugin)$/ }
  54. public_files = ["public/.htaccess"] + Dir["#{root}/public/**/*"]
  55. test_files = ["config/cucumber.yml"]
  56. files = base_dirs + text_files + environments + bundler_compatibility_files + schema_file + scripts + public_files + test_files
  57. files.map! { |f| f = $1 if f =~ %r{^#{root}/(.+)$}; f }
  58. files.sort!
  59. files.each do |file|
  60. case
  61. when File.directory?("#{root}/#{file}")
  62. m.directory file
  63. when file =~ %r{^script/}
  64. m.file radiant_root(file), file, script_options
  65. when file =~ %r{^public/dispatch}
  66. m.file radiant_root(file), file, dispatcher_options
  67. else
  68. m.file radiant_root(file), file
  69. end
  70. end
  71. # script/generate
  72. m.file "instance_generate", "script/generate", script_options
  73. # database.yml and .htaccess
  74. m.template "databases/#{options[:db]}.yml", "config/database.yml", :assigns => {
  75. :app_name => File.basename(File.expand_path(@destination_root)),
  76. :socket => options[:db] == "mysql" ? mysql_socket_location : nil
  77. }
  78. # Instance Gemfile
  79. m.template "instance_gemfile", "Gemfile", :assigns => {
  80. :radiant_version => TrustyCms::VERSION.to_s,
  81. :db => options[:db]
  82. }
  83. # Instance Rakefile
  84. m.file "instance_rakefile", "Rakefile"
  85. # Config.ru is useful in rack-based situations like Pow
  86. m.file "instance_config.ru", "config.ru"
  87. # Instance Configurations
  88. m.file "instance_routes.rb", "config/routes.rb"
  89. m.template "instance_environment.rb", "config/environment.rb", :assigns => {
  90. :radiant_environment => File.join(File.dirname(__FILE__), 'templates', radiant_root("config/environment.rb")),
  91. :app_name => File.basename(File.expand_path(@destination_root))
  92. }
  93. m.template "instance_boot.rb", "config/boot.rb"
  94. m.file "instance_radiant_config.rb", "config/initializers/radiant_config.rb"
  95. # Run bundler
  96. m.run_bundler @destination_root
  97. m.readme radiant_root("INSTALL.md")
  98. end
  99. end
  100. protected
  101. def banner
  102. "Usage: #{$0} /path/to/trusty_cms/app [options]"
  103. end
  104. def add_options!(opt)
  105. opt.separator ''
  106. opt.separator 'Options:'
  107. opt.on(
  108. "-r", "--ruby=path", String,
  109. "Path to the Ruby binary of your choice (otherwise scripts use env, dispatchers current path).",
  110. "Default: #{DEFAULT_SHEBANG}"
  111. ) { |v| options[:shebang] = v }
  112. opt.on(
  113. "-d", "--database=name", String,
  114. "Preconfigure for selected database (options: #{DATABASES.join(", ")}).",
  115. "Default: sqlite3"
  116. ) { |v| options[:db] = v }
  117. end
  118. def mysql_socket_location
  119. RUBY_PLATFORM =~ /mswin32/ ? MYSQL_SOCKET_LOCATIONS.find { |f| File.exist?(f) } : nil
  120. end
  121. private
  122. def radiant_root(filename = '')
  123. File.join("..", "..", "..", "..", filename)
  124. end
  125. end

lib/generators/instance/templates/instance_boot.rb

0.0% lines covered

97 relevant lines. 0 lines covered and 97 lines missed.
    
  1. # Don't change this file!
  2. # Configure your app in config/environment.rb and config/environments/*.rb
  3. Rails.root = "#{File.dirname(__FILE__)}/.." unless defined?(Rails.root)
  4. Rails.env = ENV.fetch('RAILS_ENV', 'development').dup unless defined?(Rails.env)
  5. module Rails
  6. class << self
  7. def vendor_rails?
  8. File.exist?("#{Rails.root}/vendor/rails")
  9. end
  10. end
  11. end
  12. module TrustyCms
  13. class << self
  14. def boot!
  15. unless booted?
  16. preinitialize
  17. pick_boot.run
  18. end
  19. end
  20. def booted?
  21. defined? TrustyCms::Initializer
  22. end
  23. def pick_boot
  24. case
  25. when app?
  26. AppBoot.new
  27. when vendor?
  28. VendorBoot.new
  29. else
  30. GemBoot.new
  31. end
  32. end
  33. def vendor?
  34. File.exist?("#{Rails.root}/vendor/radiant")
  35. end
  36. def app?
  37. File.exist?("#{Rails.root}/lib/radiant.rb")
  38. end
  39. def preinitialize
  40. load(preinitializer_path) if File.exist?(preinitializer_path)
  41. end
  42. def loaded_via_gem?
  43. pick_boot.is_a? GemBoot
  44. end
  45. def preinitializer_path
  46. "#{Rails.root}/config/preinitializer.rb"
  47. end
  48. end
  49. class Boot
  50. def run
  51. load_mutex
  52. load_initializer
  53. end
  54. # RubyGems from version 1.6 does not require thread but Rails depend on it
  55. # This should newer rails do automaticly
  56. def load_mutex
  57. begin
  58. require "thread" unless defined?(Mutex)
  59. rescue LoadError => e
  60. $stderr.puts %(Mutex could not be initialized. #{load_error_message})
  61. exit 1
  62. end
  63. end
  64. def load_initializer
  65. begin
  66. require 'trusty_cms'
  67. require 'trusty_cms/initializer'
  68. rescue LoadError => e
  69. $stderr.puts %(TrustyCms could not be initialized. #{load_error_message})
  70. exit 1
  71. end
  72. TrustyCms::Initializer.run(:set_load_path)
  73. TrustyCms::Initializer.run(:install_gem_spec_stubs)
  74. Rails::GemDependency.add_frozen_gem_path
  75. end
  76. end
  77. class VendorBoot < Boot
  78. def load_initializer
  79. $LOAD_PATH.unshift "#{Rails.root}/vendor/trusty_cms/lib"
  80. super
  81. end
  82. def load_error_message
  83. "Please verify that vendor/radiant contains a complete copy of the TrustyCms sources."
  84. end
  85. end
  86. class AppBoot < Boot
  87. def load_initializer
  88. $LOAD_PATH.unshift "#{Rails.root}/lib"
  89. super
  90. end
  91. def load_error_message
  92. "Please verify that you have a complete copy of the TrustyCms sources."
  93. end
  94. end
  95. class GemBoot < Boot
  96. # The location and version of the radiant gem should be set in your Gemfile
  97. def load_error_message
  98. "Have you run `bundle install`?'."
  99. end
  100. end
  101. end
  102. # All that for this:
  103. TrustyCms.boot!

lib/generators/instance/templates/instance_environment.rb

0.0% lines covered

33 relevant lines. 0 lines covered and 33 lines missed.
    
  1. # Be sure to restart your server when you modify this file
  2. # Uncomment below to force Rails into production mode when
  3. # you don't control web/app server and can't set it the proper way
  4. # ENV['RAILS_ENV'] ||= 'production'
  5. # Specifies gem version of Rails to use when vendor/rails is not present
  6. require File.join(File.dirname(__FILE__), 'boot')
  7. require 'radius'
  8. YAML::ENGINE.yamler = 'syck' if RUBY_VERSION =~ /1.9/
  9. TrustyCms::Initializer.run do |config|
  10. # Skip frameworks you're not going to use (only works if using vendor/rails).
  11. # To use Rails without a database, you must remove the Active Record framework
  12. # config.frameworks -= [ :action_mailer ]
  13. # Only load the extensions named here, in the order given. By default all
  14. # extensions in vendor/extensions are loaded, in alphabetical order. :all
  15. # can be used as a placeholder for all extensions not explicitly named.
  16. # config.extensions = [ :all ]
  17. # Unload the extensions named here.
  18. # config.ignore_extensions []
  19. # Your secret key for verifying cookie session data integrity.
  20. # If you change this key, all old sessions will become invalid!
  21. # Make sure the secret is at least 30 characters and all random,
  22. # no regular words or you'll be exposed to dictionary attacks.
  23. config.action_controller.session = {
  24. :key => '_<%= app_name %>_session',
  25. :secret => <% require 'digest/sha1' %>'<%= Digest::SHA1.hexdigest("--#{app_name}--#{Time.now.to_s}--#{rand(10000000)}--") %>'
  26. }
  27. # Comment out this line if you want to turn off all caching, or
  28. # add options to modify the behavior. In the majority of deployment
  29. # scenarios it is desirable to leave TrustyCms's cache enabled and in
  30. # the default configuration.
  31. #
  32. # Additional options:
  33. # :use_x_sendfile => true
  34. # Turns on X-Sendfile support for Apache with mod_xsendfile or lighttpd.
  35. # :use_x_accel_redirect => '/some/virtual/path'
  36. # Turns on X-Accel-Redirect support for nginx. You have to provide
  37. # a path that corresponds to a virtual location in your webserver
  38. # configuration.
  39. # :entitystore => "radiant:tmp/cache/entity"
  40. # Sets the entity store type (preceding the colon) and storage
  41. # location (following the colon, relative to Rails.root).
  42. # We recommend you use radiant: since this will enable manual expiration.
  43. # :metastore => "radiant:tmp/cache/meta"
  44. # Sets the meta store type and storage location. We recommend you use
  45. # radiant: since this will enable manual expiration and acceleration headers.
  46. config.middleware.use Rack::Cache,
  47. :private_headers => ['Authorization'],
  48. :entitystore => "radiant:tmp/cache/entity",
  49. :metastore => "radiant:tmp/cache/meta",
  50. :verbose => false,
  51. :allow_reload => false,
  52. :allow_revalidate => false
  53. config.middleware.insert_before(Rack::ConditionalGet, Rack::Cache)
  54. config.assets.enabled = true
  55. # Use the database for sessions instead of the cookie-based default,
  56. # which shouldn't be used to store highly confidential information
  57. # (create the session table with 'rake db:sessions:create')
  58. config.action_controller.session_store = :cookie_store
  59. # Activate observers that should always be running
  60. config.active_record.observers = :user_action_observer
  61. # Make Active Record use UTC-base instead of local time
  62. config.time_zone = 'UTC'
  63. # Set the default field error proc
  64. config.action_view.field_error_proc = Proc.new do |html, instance|
  65. if html !~ /label/
  66. %{<span class="error-with-field">#{html} <span class="error">#{[instance.error_message].flatten.first}</span></span>}.html_safe
  67. else
  68. html
  69. end
  70. end
  71. config.after_initialize do
  72. # Add new inflection rules using the following format:
  73. ActiveSupport::Inflector.inflections do |inflect|
  74. inflect.uncountable 'config'
  75. end
  76. end
  77. end

lib/generators/instance/templates/instance_radiant_config.rb

0.0% lines covered

2 relevant lines. 0 lines covered and 2 lines missed.
    
  1. TrustyCms.config do |config|
  2. # this file can be used to set defaults, options and validation rules for local configuration settings.
  3. # core settings are defined in TRUSTY_CMS_ROOT/config/initializers/radiant_config.rb and by the corresponding
  4. # file in each radiant extension. You probably don't need to add anything here, but in case you do:
  5. # config.define 'site.show_footer?', :default => "true"
  6. # config.define 'S3.bucket', :default => "key", :allow_change => false
  7. # you can also use this file to set config values (by environment, for example):
  8. # if Rails.env == 'production'
  9. # config['cache.duration'] = 86400
  10. # else
  11. # config['cache.duration'] = 0
  12. # end
  13. end

lib/generators/instance/templates/instance_routes.rb

0.0% lines covered

1 relevant lines. 0 lines covered and 1 lines missed.
    
  1. load File.join(TRUSTY_CMS_ROOT, "config", "routes.rb")

lib/generators/language_extension/language_extension_generator.rb

0.0% lines covered

52 relevant lines. 0 lines covered and 52 lines missed.
    
  1. class LanguageExtensionGenerator < Rails::Generator::NamedBase
  2. default_options :with_test_unit => false
  3. attr_reader :extension_path, :extension_file_name, :localization_name
  4. def initialize(runtime_args, runtime_options = {})
  5. super
  6. @extension_file_name = "#{file_name}_language_pack_extension"
  7. @extension_path = "vendor/extensions/#{file_name}_language_pack"
  8. @localization_name = localization_name
  9. end
  10. def manifest
  11. record do |m|
  12. m.directory "#{extension_path}/config/locales"
  13. m.directory "#{extension_path}/lib/tasks"
  14. m.template 'README', "#{extension_path}/README"
  15. m.template 'extension.rb', "#{extension_path}/#{extension_file_name}.rb"
  16. # m.template 'tasks.rake', "#{extension_path}/lib/tasks/#{extension_file_name}_tasks.rake"
  17. m.template 'lang.yml', "#{extension_path}/config/locales/#{localization_name}.yml"
  18. m.template 'available_tags.yml', "#{extension_path}/config/locales/#{localization_name}_available_tags.yml"
  19. m.template 'lib.rb', "#{extension_path}/lib/radiant-#{file_name}_language_pack-extension.rb"
  20. m.template 'gemspec.rb', "#{extension_path}/radiant-#{file_name}_language_pack-extension.gemspec"
  21. end
  22. end
  23. def class_name
  24. super.to_name.gsub(' ', '') + 'LanguagePackExtension'
  25. end
  26. def extension_name
  27. class_name.to_name('Extension')
  28. end
  29. def author_info
  30. @author_info ||= begin
  31. Git.global_config
  32. rescue NameError
  33. {}
  34. end
  35. end
  36. def homepage
  37. author_info['github.user'] ? "http://github.com/#{author_info['github.user']}/radiant-#{file_name}-extension" : "http://example.com/#{file_name}"
  38. end
  39. def author_email
  40. author_info['user.email'] || 'your email'
  41. end
  42. def author_name
  43. author_info['user.name'] || 'Your Name'
  44. end
  45. def add_options!(opt)
  46. # opt.separator ''
  47. # opt.separator 'Options:'
  48. # opt.on("--with-test-unit",
  49. # "Use Test::Unit for this extension instead of RSpec") { |v| options[:with_test_unit] = v }
  50. end
  51. def localization_name
  52. file_name.split('_')[1] ? "#{file_name.split('_')[0]}-#{file_name.split('_')[1].upcase}" : file_name
  53. end
  54. def copy_files
  55. FileUtils.cp("#{TRUSTY_CMS_ROOT}/config/locales/en_available_tags.yml","#{TRUSTY_CMS_ROOT}/#{extension_path}/config/locales/#{localization_name}_available_tags.yml")
  56. end
  57. end

lib/generators/language_extension/templates/cucumber_env.rb

0.0% lines covered

10 relevant lines. 0 lines covered and 10 lines missed.
    
  1. # Sets up the Rails environment for Cucumber
  2. ENV["Rails.env"] = "test"
  3. # Extension root
  4. extension_env = File.expand_path(File.dirname(__FILE__) + '/../../../../../config/environment')
  5. require extension_env+'.rb'
  6. Dir.glob(File.join(TRUSTY_CMS_ROOT, "features", "**", "*.rb")).each {|step| require step}
  7. Cucumber::Rails::World.class_eval do
  8. include Dataset
  9. datasets_directory "#{TRUSTY_CMS_ROOT}/spec/datasets"
  10. Dataset::Resolver.default = Dataset::DirectoryResolver.new("#{TRUSTY_CMS_ROOT}/spec/datasets", File.dirname(__FILE__) + '/../../spec/datasets', File.dirname(__FILE__) + '/../datasets')
  11. self.datasets_database_dump_path = "#{Rails.root}/tmp/dataset"
  12. # dataset :<%= file_name %>
  13. end

lib/generators/language_extension/templates/cucumber_paths.rb

0.0% lines covered

10 relevant lines. 0 lines covered and 10 lines missed.
    
  1. def path_to(page_name)
  2. case page_name
  3. when /the homepage/i
  4. root_path
  5. when /login/i
  6. login_path
  7. # Add more page name => path mappings here
  8. else
  9. raise "Can't find mapping from \"#{page_name}\" to a path."
  10. end
  11. end

lib/generators/language_extension/templates/extension.rb

0.0% lines covered

8 relevant lines. 0 lines covered and 8 lines missed.
    
  1. # Uncomment this if you reference any of your controllers in activate
  2. require "radiant-<%= file_name %>_language_pack-extension"
  3. class <%= class_name %> < TrustyCms::Extension
  4. version TrustyCms<%= class_name %>::VERSION
  5. description TrustyCms<%= class_name %>::DESCRIPTION
  6. url TrustyCms<%= class_name %>::URL
  7. def activate
  8. end
  9. end

lib/generators/language_extension/templates/functional_test.rb

0.0% lines covered

10 relevant lines. 0 lines covered and 10 lines missed.
    
  1. require File.dirname(__FILE__) + '/../test_helper'
  2. class <%= class_name %>Test < Test::Unit::TestCase
  3. # Replace this with your real tests.
  4. def test_this_extension
  5. flunk
  6. end
  7. def test_initialization
  8. assert_equal File.join(File.expand_path(Rails.root), 'vendor', 'extensions', '<%= file_name %>'), <%= class_name %>.root
  9. assert_equal '<%= extension_name %>', <%= class_name %>.extension_name
  10. end
  11. end

lib/generators/language_extension/templates/gemspec.rb

0.0% lines covered

20 relevant lines. 0 lines covered and 20 lines missed.
    
  1. # -*- encoding: utf-8 -*-
  2. $:.push File.expand_path("../lib", __FILE__)
  3. require "radiant-<%= file_name %>_language_pack-extension"
  4. Gem::Specification.new do |s|
  5. s.name = "radiant-<%= file_name %>_language_pack-extension"
  6. s.version = TrustyCms<%= class_name %>::VERSION
  7. s.platform = Gem::Platform::RUBY
  8. s.authors = TrustyCms<%= class_name %>::AUTHORS
  9. s.email = TrustyCms<%= class_name %>::EMAIL
  10. s.homepage = TrustyCms<%= class_name %>::URL
  11. s.summary = TrustyCms<%= class_name %>::SUMMARY
  12. s.description = TrustyCms<%= class_name %>::DESCRIPTION
  13. ignores = if File.exist?('.gitignore')
  14. File.read('.gitignore').split("\n").inject([]) {|a,p| a + Dir[p] }
  15. else
  16. []
  17. end
  18. s.files = Dir['**/*'] - ignores
  19. s.test_files = Dir['test/**/*','spec/**/*','features/**/*'] - ignores
  20. # s.executables = Dir['bin/*'] - ignores
  21. s.require_paths = ["lib"]
  22. end

lib/generators/language_extension/templates/lib.rb

0.0% lines covered

8 relevant lines. 0 lines covered and 8 lines missed.
    
  1. module TrustyCms<%= class_name %>
  2. VERSION = "1.0.0"
  3. SUMMARY = "<%= localization_name.capitalize %> language pack for TrustyCms CMS"
  4. DESCRIPTION = "Adds <%= localization_name.capitalize %> translations to the TrustyCms CMS interface."
  5. URL = "<%= homepage %>"
  6. AUTHORS = ["<%= author_name %>"]
  7. EMAIL = ["<%= author_email %>"]
  8. end

lib/generators/language_extension/templates/spec_helper.rb

0.0% lines covered

18 relevant lines. 0 lines covered and 18 lines missed.
    
  1. unless defined? TRUSTY_CMS_ROOT
  2. ENV["Rails.env"] = "test"
  3. case
  4. when ENV.fetch('RADIANT_ENV_FILE')
  5. require ENV.fetch('RADIANT_ENV_FILE')
  6. when File.dirname(__FILE__) =~ %r{vendor/trusty_cms/vendor/extensions}
  7. require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
  8. else
  9. require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
  10. end
  11. end
  12. require "#{TRUSTY_CMS_ROOT}/spec/spec_helper"
  13. Dataset::Resolver.default << (File.dirname(__FILE__) + "/datasets")
  14. if File.directory?(File.dirname(__FILE__) + "/matchers")
  15. Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
  16. end
  17. Spec::Runner.configure do |config|
  18. # config.use_transactional_fixtures = true
  19. # config.use_instantiated_fixtures = false
  20. # config.fixture_path = Rails.root + '/spec/fixtures'
  21. # You can declare fixtures for each behaviour like this:
  22. # describe "...." do
  23. # fixtures :table_a, :table_b
  24. #
  25. # Alternatively, if you prefer to declare them only once, you can
  26. # do so here, like so ...
  27. #
  28. # config.global_fixtures = :table_a, :table_b
  29. #
  30. # If you declare global fixtures, be aware that they will be declared
  31. # for all of your examples, even those that don't use them.
  32. end

lib/generators/language_extension/templates/test_helper.rb

0.0% lines covered

17 relevant lines. 0 lines covered and 17 lines missed.
    
  1. require 'test/unit'
  2. # Load the environment
  3. unless defined? TRUSTY_CMS_ROOT
  4. ENV["Rails.env"] = "test"
  5. case
  6. when ENV.fetch('RADIANT_ENV_FILE')
  7. require ENV.fetch('RADIANT_ENV_FILE')
  8. when File.dirname(__FILE__) =~ %r{vendor/trusty_cms/vendor/extensions}
  9. require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
  10. else
  11. require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
  12. end
  13. end
  14. require "#{TRUSTY_CMS_ROOT}/test/test_helper"
  15. class Test::Unit::TestCase
  16. # Include a helper to make testing Radius tags easier
  17. test_helper :extension_tags
  18. # Add the fixture directory to the fixture path
  19. self.fixture_path << File.dirname(__FILE__) + "/fixtures"
  20. # Add more helper methods to be used by all extension tests here...
  21. end

lib/generators/trusty_cms/trusty_cms_generator.rb

0.0% lines covered

24 relevant lines. 0 lines covered and 24 lines missed.
    
  1. class TrustyCmsGenerator < Rails::Generators::Base
  2. source_root File.expand_path('../templates', __FILE__)
  3. argument :project_name, type: :string, default: "trusty"
  4. def generate_config
  5. template "Rakefile.erb", "Rakefile"
  6. template "config.ru.erb", "config.ru"
  7. template "boot.rb.erb", "config/boot.rb"
  8. template "environment.rb.erb", "config/environment.rb"
  9. template "application.rb.erb", "config/application.rb"
  10. template "preinitializer.rb.erb", "config/preinitializer.rb"
  11. template "routes.rb.erb", "config/routes.rb"
  12. template "database.yml.erb", "config/database.yml"
  13. template "environments/development.rb.erb", "config/environments/development.rb"
  14. template "environments/test.rb.erb", "config/environments/test.rb"
  15. template "environments/production.rb.erb", "config/environments/production.rb"
  16. template "initializers/trusty_cms_config.rb.erb", "config/initializers/trusty_cms_config.rb"
  17. template "initializers/secret_token.rb.erb", "config/initializers/secret_token.rb"
  18. template "initializers/session_store.rb.erb", "config/initializers/session_store.rb"
  19. remove_file 'app/controllers/application_controller.rb'
  20. remove_file 'app/helpers/application_helper.rb'
  21. remove_file 'app/assets/javascripts/application.js'
  22. remove_file 'app/views/layouts/application.html.erb'
  23. end
  24. end

lib/inheritable_class_attributes.rb

0.0% lines covered

61 relevant lines. 0 lines covered and 61 lines missed.
    
  1. module InheritableClassAttributes
  2. def self.included(base)
  3. base.extend ClassMethods
  4. base.module_eval do
  5. class << self
  6. alias inherited_without_inheritable_class_attributes inherited
  7. alias inherited inherited_with_inheritable_class_attributes
  8. end
  9. end
  10. end
  11. module ClassMethods
  12. def inheritable_cattr_readers
  13. @inheritable_class_readers ||= []
  14. end
  15. def inheritable_cattr_writers
  16. @inheritable_class_writers ||= []
  17. end
  18. def cattr_inheritable_reader(*symbols)
  19. symbols.each do |symbol|
  20. inheritable_cattr_readers << symbol
  21. module_eval %{
  22. def self.#{symbol}
  23. @#{symbol}
  24. end
  25. }
  26. end
  27. inheritable_cattr_readers.uniq!
  28. end
  29. def cattr_inheritable_writer(*symbols)
  30. symbols.each do |symbol|
  31. inheritable_cattr_writers << symbol
  32. module_eval %{
  33. def self.#{symbol}=(value)
  34. @#{symbol} = value
  35. end
  36. }
  37. end
  38. inheritable_cattr_writers.uniq!
  39. end
  40. def cattr_inheritable_accessor(*symbols)
  41. cattr_inheritable_writer(*symbols)
  42. cattr_inheritable_reader(*symbols)
  43. end
  44. def inherited_with_inheritable_class_attributes(klass)
  45. inherited_without_inheritable_class_attributes(klass) if respond_to?(:inherited_without_inheritable_class_attributes)
  46. readers = inheritable_cattr_readers.dup
  47. writers = inheritable_cattr_writers.dup
  48. inheritables = %i[inheritable_cattr_readers inheritable_cattr_writers]
  49. (readers + writers + inheritables).uniq.each do |attr|
  50. var = "@#{attr}"
  51. old_value = module_eval(var)
  52. new_value = (begin
  53. old_value.dup
  54. rescue StandardError
  55. old_value
  56. end)
  57. klass.module_eval("#{var} = new_value")
  58. end
  59. end
  60. end
  61. end

lib/login_system.rb

0.0% lines covered

83 relevant lines. 0 lines covered and 83 lines missed.
    
  1. module LoginSystem
  2. def self.included(base)
  3. base.extend ClassMethods
  4. base.class_eval do
  5. # prepend_before_action :authenticate
  6. # prepend_before_action :authorize
  7. # helper_method :current_user
  8. end
  9. end
  10. protected
  11. # def current_user
  12. # end
  13. # def current_user=(value=nil)
  14. # if value && value.is_a?(User)
  15. # @current_user = value
  16. # session['user_id'] = value.id
  17. # else
  18. # @current_user = nil
  19. # session['user_id'] = nil
  20. # end
  21. # @current_user
  22. # end
  23. def authenticate
  24. # puts _process_action_callbacks.map(&:filter)
  25. # if current_user
  26. # session['user_id'] = current_user.id
  27. # true
  28. # else
  29. # session[:return_to] = request.original_url
  30. # respond_to do |format|
  31. # format.html { redirect_to login_url }
  32. # format.any(:xml,:json) { request_http_basic_authentication }
  33. # end
  34. # false
  35. # end
  36. true
  37. end
  38. def authorize_role
  39. action = action_name.to_s.intern
  40. return true if user_has_access_to_action?(action)
  41. handle_unauthorized_access(action)
  42. false
  43. end
  44. def user_has_access_to_action?(action)
  45. self.class.user_has_access_to_action?(current_user, action, self)
  46. end
  47. def handle_unauthorized_access(action)
  48. permissions = self.class.controller_permissions[action]
  49. flash[:error] = permissions[:denied_message] || 'Access denied.'
  50. respond_to do |format|
  51. format.html { redirect_to(permissions[:denied_url] || { action: :index }) }
  52. format.any(:xml, :json) { head :forbidden }
  53. end
  54. end
  55. def login_from_session
  56. User.unscoped.find(session['user_id'])
  57. rescue StandardError
  58. nil
  59. end
  60. def login_from_cookie
  61. if !cookies[:session_token].blank? && user = User.find_by_session_token(cookies[:session_token]) # don't find by empty value
  62. user.remember_me
  63. set_session_cookie(user)
  64. user
  65. end
  66. end
  67. def login_from_http
  68. if [Mime[:xml], Mime[:json]].include?(request.format)
  69. authenticate_with_http_basic do |user_name, password|
  70. User.authenticate(user_name, password)
  71. end
  72. end
  73. end
  74. def set_session_cookie(user = current_user)
  75. cookies[:session_token] = { value: user.session_token, expires: (Time.now + (TrustyCms::Config['session_timeout'].to_i / 86400).days).utc }
  76. end
  77. module ClassMethods
  78. def login_required?
  79. filter_chain.any? { |f| f.method == :authenticate || f.method == :authorize }
  80. end
  81. def login_required
  82. unless login_required?
  83. prepend_before_action :authenticate, :authorize
  84. end
  85. end
  86. def only_allow_access_to(*args)
  87. options = {}
  88. options = args.pop.dup if args.last.is_a?(Hash)
  89. options.symbolize_keys!
  90. actions = args.map { |a| a.to_s.intern }
  91. actions.each do |action|
  92. controller_permissions[action] = options
  93. end
  94. end
  95. def controller_permissions
  96. @controller_permissions ||= Hash.new { |h, k| h[k.to_s.intern] = Hash.new }
  97. end
  98. def user_has_access_to_action?(user, action, instance = new)
  99. permissions = controller_permissions[action.to_s.intern]
  100. if allowed_roles = permissions[:when]
  101. allowed_roles = [allowed_roles].flatten
  102. user.present? ? allowed_roles.any? { |role| user.role?(role) } : false
  103. elsif condition_method = permissions[:if]
  104. instance.send(condition_method)
  105. else
  106. true
  107. end
  108. end
  109. end
  110. end

lib/method_observer.rb

0.0% lines covered

42 relevant lines. 0 lines covered and 42 lines missed.
    
  1. class MethodObserver
  2. attr_reader :target
  3. attr_accessor :result
  4. class ObserverCannotObserveTwiceError < StandardError
  5. def initialize(message = 'observer cannot observe twice')
  6. super
  7. end
  8. end
  9. def observe(target)
  10. raise ObserverCannotObserveTwiceError if @target
  11. @target = target
  12. make_observable(target)
  13. end
  14. def self.instances
  15. @instances ||= {}
  16. end
  17. def self.new(*args)
  18. o = super
  19. instances[o.object_id] = o
  20. o
  21. end
  22. private
  23. def make_observable(target)
  24. methods_to_observe.each do |method|
  25. target.instance_eval %{
  26. def #{method}(*args, &block)
  27. observer = #{self.class}.instances[#{object_id}]
  28. observer.send(:before_#{method}, *args, &block) if observer.respond_to? :before_#{method}
  29. observer.result = super
  30. observer.send(:after_#{method}, *args, &block) if observer.respond_to? :after_#{method}
  31. observer.result
  32. end
  33. }
  34. end
  35. end
  36. def methods_to_observe
  37. (methods_for(:before) + methods_for(:after)).uniq
  38. end
  39. def methods_for(name)
  40. methods.grep(/^#{name}_/).map { |n| n.to_s.gsub(/^#{name}_/, '').intern }
  41. end
  42. end

lib/ostruct.rb

0.0% lines covered

44 relevant lines. 0 lines covered and 44 lines missed.
    
  1. # patching OpenStruct due to Ruby 2.3.1 upgrade
  2. # See more here: http://stackoverflow.com/questions/39278864/openstruct-issue-with-ruby-2-3-1/39280374#39280374
  3. class OpenStruct
  4. def initialize(hash = nil)
  5. @table = {}
  6. hash&.each_pair do |k, v|
  7. k = k.to_sym
  8. @table[k] = v
  9. new_ostruct_member(k)
  10. end
  11. end
  12. def modifiable
  13. begin
  14. @modifiable = true
  15. rescue StandardError
  16. raise RuntimeError, "can't modify frozen #{self.class}", caller(3)
  17. end
  18. @table
  19. end
  20. protected :modifiable
  21. def new_ostruct_member(name)
  22. name = name.to_sym
  23. unless respond_to?(name)
  24. define_singleton_method(name) { @table[name] }
  25. define_singleton_method("#{name}=") { |x| modifiable[name] = x }
  26. end
  27. name
  28. end
  29. protected :new_ostruct_member
  30. def method_missing(mid, *args) # :nodoc:
  31. mname = mid.id2name
  32. len = args.length
  33. if mname.chomp!('=')
  34. if len != 1
  35. raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
  36. end
  37. modifiable[new_ostruct_member(mname)] = args[0]
  38. elsif len == 0
  39. @table[mid]
  40. else
  41. err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
  42. err.set_backtrace caller(1)
  43. raise err
  44. end
  45. end
  46. end

lib/simpleton.rb

0.0% lines covered

15 relevant lines. 0 lines covered and 15 lines missed.
    
  1. module Simpleton
  2. def self.included(base)
  3. base.extend(ClassMethods)
  4. end
  5. module ClassMethods
  6. def instance(&block)
  7. @instance ||= new
  8. block.call(@instance) if block_given?
  9. @instance
  10. end
  11. def method_missing(method, *args, &block)
  12. instance.respond_to?(method) ? instance.send(method, *args, &block) : super
  13. end
  14. end
  15. end

lib/string_extensions/string_extensions.rb

0.0% lines covered

20 relevant lines. 0 lines covered and 20 lines missed.
    
  1. require 'stringex'
  2. class String
  3. def symbolize
  4. gsub(/[^A-Za-z0-9]+/, '_').gsub(/(^_+|_+$)/, '').underscore.to_sym
  5. end
  6. def titlecase
  7. gsub(/((?:^|\s)[a-z])/) { $1.to_s.upcase }
  8. end
  9. def to_name(last_part = '')
  10. underscore.gsub('/', ' ').humanize.titlecase.gsub(/\s*#{last_part}$/, '')
  11. end
  12. unless methods.include?('parameterize')
  13. def parameterize(sep = '-')
  14. remove_formatting.downcase.replace_whitespace(sep).collapse(sep)
  15. end
  16. end
  17. alias :to_slug :parameterize
  18. alias :slugify :parameterize
  19. alias :slugerize :parameterize
  20. end

lib/symbol_extensions/symbol_extensions.rb

0.0% lines covered

5 relevant lines. 0 lines covered and 5 lines missed.
    
  1. class Symbol
  2. def symbolize
  3. to_s.symbolize
  4. end
  5. end

lib/translation_support.rb

0.0% lines covered

44 relevant lines. 0 lines covered and 44 lines missed.
    
  1. class TranslationSupport
  2. class << self
  3. # Retrieve US word set
  4. def get_translation_keys(language_root, suffix = nil)
  5. (dummy_comments, words) = read_file("#{language_root}/en#{suffix}.yml", 'en')
  6. words
  7. end
  8. # Retrieve comments, translation data in hash form
  9. def read_file(filename, basename)
  10. (comments, data) = File.read(filename).split(/\n#{basename}:\s*\n/) # Add error checking for failed file read?
  11. [comments, create_hash(data, basename)]
  12. end
  13. # Creates hash of translation data
  14. def create_hash(data, _basename)
  15. words = Hash.new
  16. return words if !data
  17. parent = Array.new
  18. previous_key = 'base'
  19. data.split("\n").each do |w|
  20. next if w.strip.blank?
  21. (key, value) = w.split(':', 2)
  22. value ||= ''
  23. shift = (key =~ /\w/) / 2 - parent.size # Determine level of current key in comparison to parent array
  24. key = key.sub(/^\s+/, '')
  25. parent << previous_key if shift > 0 # If key is child of previous key, add previous key as parent
  26. (shift * -1).times { parent.pop } if shift < 0 # If key is not related to previous key, remove parent keys
  27. previous_key = key # Track key in case next key is child of this key
  28. words[parent.join(':') + ':' + key] = value unless key.blank?
  29. end
  30. words
  31. end
  32. def open_available_tags(filename)
  33. data = YAML::load(File.open(filename.to_s))
  34. data.to_s
  35. end
  36. # Writes to file from translation data hash structure
  37. def write_file(filename, basename, comments, words)
  38. File.open(filename, 'w') do |log|
  39. log.puts(comments + "\n" + basename + ": \n")
  40. words.sort.each do |k, v|
  41. keys = k.split(':')
  42. (keys.size - 1).times { keys[keys.size - 1] = ' ' + keys[keys.size - 1] } # Add indentation for children keys
  43. log.puts(keys[keys.size - 1] + ':' + v + "\n")
  44. end
  45. end
  46. end
  47. end
  48. end

lib/trusty_cms.rb

0.0% lines covered

5 relevant lines. 0 lines covered and 5 lines missed.
    
  1. require 'trusty_cms/version'
  2. require 'trusty_cms/engine'
  3. module TrustyCms
  4. end
  5. TRUSTY_CMS_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')) unless defined? TRUSTY_CMS_ROOT

lib/trusty_cms/admin_ui.rb

0.0% lines covered

213 relevant lines. 0 lines covered and 213 lines missed.
    
  1. require 'simpleton'
  2. require 'ostruct'
  3. module TrustyCms
  4. class AdminUI
  5. # This may be loaded before ActiveSupport, so do an explicit require
  6. require 'trusty_cms/admin_ui/region_set'
  7. class DuplicateTabNameError < StandardError; end
  8. # The NavTab Class holds the structure of a navigation tab (including
  9. # its sub-nav items).
  10. class NavTab < Array
  11. attr_reader :name
  12. def initialize(name)
  13. @name = name
  14. end
  15. def [](id)
  16. if id.is_a? Integer
  17. super
  18. else
  19. find { |subnav_item| subnav_item.name.to_s.titleize == id.to_s.titleize }
  20. end
  21. end
  22. def <<(*args)
  23. options = args.extract_options!
  24. item = args.size > 1 ? deprecated_add(*(args << caller)) : args.first
  25. raise DuplicateTabNameError.new("duplicate tab name `#{item.name}'") if self[item.name]
  26. item.tab = self if item.respond_to?(:tab=)
  27. if options.empty?
  28. super(item)
  29. else
  30. options.symbolize_keys!
  31. before = options.delete(:before)
  32. after = options.delete(:after)
  33. tab_name = before || after
  34. if self[tab_name]
  35. _index = index(self[tab_name])
  36. _index += 1 unless before
  37. insert(_index, item)
  38. else
  39. super(item)
  40. end
  41. end
  42. end
  43. alias :add :<<
  44. def add_item(*args)
  45. options = args.extract_options!
  46. options.symbolize_keys!
  47. before = options.delete(:before)
  48. after = options.delete(:after)
  49. tab_name = before || after
  50. if self[tab_name]
  51. _index = index(self[tab_name])
  52. _index += 1 unless before
  53. insert(_index, NavSubItem.new(args.first, args.second))
  54. else
  55. add NavSubItem.new(args.first, args.second)
  56. end
  57. end
  58. def visible?(user)
  59. any? { |sub_item| sub_item.visible?(user) }
  60. end
  61. def deprecated_add(name, url, caller)
  62. ActiveSupport::Deprecation.warn("admin.tabs.add is no longer supported in TrustyCms 0.9.x. Please update your code to use: \ntab \"Content\" do\n\tadd_item(...)\nend", caller)
  63. NavSubItem.new(name, url)
  64. end
  65. end
  66. # Simple structure for storing the properties of a tab's sub items.
  67. class NavSubItem
  68. attr_reader :name, :url
  69. attr_accessor :tab
  70. def initialize(name, url = '#')
  71. @name = name
  72. @url = url
  73. end
  74. def visible?(user)
  75. visible_by_controller?(user)
  76. end
  77. def relative_url
  78. File.join(ActionController::Base.relative_url_root || '', url)
  79. end
  80. private
  81. def visible_by_controller?(user)
  82. params = TrustyCms::Application.routes.recognize_path(url, method: :get)
  83. if params && params[:controller]
  84. klass = "#{params[:controller].camelize}Controller".constantize
  85. klass.user_has_access_to_action?(user, params[:action])
  86. else
  87. false
  88. end
  89. end
  90. end
  91. include Simpleton
  92. attr_accessor :nav
  93. def nav_tab(*args)
  94. NavTab.new(*args)
  95. end
  96. def nav_item(*args)
  97. NavSubItem.new(*args)
  98. end
  99. def tabs
  100. nav['Content']
  101. end
  102. # Region sets
  103. %w{page layout user configuration extension}.each do |controller|
  104. attr_accessor controller
  105. alias_method "#{controller}s", controller
  106. end
  107. def initialize
  108. initialize_nav
  109. load_default_regions
  110. end
  111. def initialize_nav
  112. @nav = NavTab.new('Tab Container')
  113. load_default_nav
  114. end
  115. def load_default_nav
  116. content = nav_tab('Content')
  117. content << nav_item('Pages', '/admin/pages')
  118. nav << content
  119. design = nav_tab('Design')
  120. design << nav_item('Layouts', '/admin/layouts')
  121. nav << design
  122. settings = nav_tab('Settings')
  123. settings << nav_item('General', '/admin/configuration')
  124. settings << nav_item('Personal', '/admin/preferences')
  125. settings << nav_item('Users', '/admin/users')
  126. settings << nav_item('Extensions', '/admin/extensions')
  127. nav << settings
  128. end
  129. def load_default_regions
  130. @page = load_default_page_regions
  131. @layout = load_default_layout_regions
  132. @user = load_default_user_regions
  133. @configuration = load_default_configuration_regions
  134. @extension = load_default_extension_regions
  135. end
  136. private
  137. def load_default_page_regions
  138. OpenStruct.new.tap do |page|
  139. page.edit = RegionSet.new do |edit|
  140. edit.main.concat %w{edit_header edit_form edit_popups}
  141. edit.form.concat %w{edit_title edit_extended_metadata edit_page_parts}
  142. edit.layout.concat %w{edit_layout edit_type edit_status edit_published_at}
  143. edit.form_bottom.concat %w{edit_buttons edit_timestamp}
  144. end
  145. page.index = RegionSet.new do |index|
  146. index.sitemap_head.concat %w{title_column_header status_column_header actions_column_header}
  147. index.node.concat %w{title_column status_column actions_column}
  148. end
  149. page.search = RegionSet.new do |search|
  150. search.sitemap_head.concat %w{title_column_header status_column_header actions_column_header}
  151. search.node.concat %w{title_column status_column actions_column}
  152. end
  153. page.remove = page.children = page.index
  154. page.new = page._part = page.edit
  155. end
  156. end
  157. def load_default_user_regions
  158. OpenStruct.new.tap do |user|
  159. user.preferences = RegionSet.new do |preferences|
  160. preferences.main.concat %w{edit_header edit_form}
  161. preferences.form.concat %w{edit_first_name edit_last_name edit_email edit_password}
  162. preferences.form_bottom.concat %w{edit_buttons}
  163. end
  164. user.edit = RegionSet.new do |edit|
  165. edit.main.concat %w{edit_header edit_form}
  166. edit.form.concat %w{edit_first_name edit_last_name edit_email edit_password
  167. edit_roles edit_notes}
  168. edit.form_bottom.concat %w{edit_buttons edit_timestamp}
  169. end
  170. user.index = RegionSet.new do |index|
  171. index.thead.concat %w{title_header roles_header actions_header last_sign_in_at_header}
  172. index.tbody.concat %w{title_cell roles_cell actions_cell last_sign_in_at_cell}
  173. index.bottom.concat %w{new_button}
  174. end
  175. user.new = user.edit
  176. user.remove = user.edit
  177. end
  178. end
  179. def load_default_layout_regions
  180. OpenStruct.new.tap do |layout|
  181. layout.edit = RegionSet.new do |edit|
  182. edit.main.concat %w{edit_header edit_form}
  183. edit.form.concat %w{edit_title edit_extended_metadata edit_content}
  184. edit.form_bottom.concat %w{reference_links edit_buttons edit_timestamp}
  185. end
  186. layout.index = RegionSet.new do |index|
  187. index.top.concat %w{}
  188. index.thead.concat %w{title_header actions_header}
  189. index.tbody.concat %w{title_cell actions_cell}
  190. index.bottom.concat %w{new_button}
  191. end
  192. layout.new = layout.edit
  193. layout.remove = layout.edit
  194. end
  195. end
  196. def load_default_configuration_regions
  197. OpenStruct.new.tap do |configuration|
  198. configuration.show = RegionSet.new do |show|
  199. show.user.concat %w{preferences}
  200. show.trusty_config.concat %w{site defaults users}
  201. end
  202. configuration.edit = RegionSet.new do |edit|
  203. edit.main.concat %w{edit_header edit_form}
  204. edit.form.concat %w{edit_site edit_defaults edit_users}
  205. edit.form_bottom.concat %w{edit_buttons}
  206. end
  207. end
  208. end
  209. def load_default_extension_regions
  210. OpenStruct.new.tap do |extension|
  211. extension.index = RegionSet.new do |index|
  212. index.thead.concat %w{title_header website_header version_header}
  213. index.tbody.concat %w{title_cell website_cell version_cell}
  214. end
  215. end
  216. end
  217. end
  218. end

lib/trusty_cms/admin_ui/region_partials.rb

0.0% lines covered

19 relevant lines. 0 lines covered and 19 lines missed.
    
  1. class TrustyCms::AdminUI::RegionPartials
  2. def initialize(template)
  3. @partials = Hash.new { |h, k| h[k] = "<strong>`#{k}' default partial not found!</strong>" }
  4. @template = template
  5. end
  6. def [](key)
  7. @partials[key.to_s]
  8. end
  9. def method_missing(method, *_args, &block)
  10. if block_given?
  11. # Ruby 1.9.2 yields self in instance_eval... see https://gist.github.com/479572
  12. # lambdas are as strict as methods in 1.9.x, making sure that the args match, Procs are not.
  13. if RUBY_VERSION =~ /^1\.9/ && block.lambda? && (block.arity != 1)
  14. raise "You can only pass a proc ('Proc.new') or a lambda that takes exactly one arg (for self) to TrustyCms::AdminUI::RegionPartials' method_missing."
  15. end
  16. @partials[method.to_s] = @template.capture(&block)
  17. else
  18. @partials[method.to_s]
  19. end
  20. end
  21. end

lib/trusty_cms/admin_ui/region_set.rb

0.0% lines covered

30 relevant lines. 0 lines covered and 30 lines missed.
    
  1. class TrustyCms::AdminUI::RegionSet
  2. def initialize
  3. @regions = Hash.new do |h, k|
  4. h[k] = []
  5. end
  6. yield self if block_given?
  7. end
  8. def [](region)
  9. @regions[region.to_sym]
  10. end
  11. def add(region = nil, partial = nil, options = {})
  12. raise ArgumentError, 'You must specify a region and a partial' unless region && partial
  13. if options[:before]
  14. index = @regions[region].empty? ? 0 : (@regions[region].index(options[:before]) || @regions[region].size)
  15. self[region].insert(index, partial)
  16. elsif options[:after]
  17. index = @regions[region].empty? ? 0 : (@regions[region].index(options[:after]) || @regions[region].size - 1)
  18. self[region].insert(index + 1, partial)
  19. else
  20. self[region] << partial
  21. end
  22. end
  23. def method_missing(method, *args, &block)
  24. if args.empty?
  25. self[method]
  26. else
  27. super
  28. end
  29. end
  30. end

lib/trusty_cms/available_locales.rb

0.0% lines covered

15 relevant lines. 0 lines covered and 15 lines missed.
    
  1. module TrustyCms::AvailableLocales
  2. # Returns the list of available locale files in options_for_select format.
  3. #
  4. def self.locales
  5. available_locales = {}
  6. TrustyCms.configuration.i18n.load_path.each do |path|
  7. if File.exist?(path) && path !~ /_available_tags/
  8. locale_yaml = YAML.load_file(path)
  9. stem = File.basename(path, '.yml')
  10. if locale_yaml[stem] && lang = locale_yaml[stem]['this_file_language']
  11. available_locales[lang] = stem
  12. end
  13. end
  14. end
  15. available_locales.collect { |k, v| [k, v] }.sort_by { |s| s[0] }
  16. end
  17. end

lib/trusty_cms/config/definition.rb

0.0% lines covered

78 relevant lines. 0 lines covered and 78 lines missed.
    
  1. module TrustyCms
  2. class Config
  3. class Definition
  4. attr_reader :empty, :default, :type, :notes, :validate_with, :select_from, :allow_blank, :allow_display, :allow_change, :units, :definer
  5. # Configuration 'definitions' are metadata held in memory that add restriction and description to individual config entries.
  6. #
  7. # By default trusty's configuration machinery is open and ad-hoc: config items are just globally-accessible variables.
  8. # They're created when first mentioned and then available in all parts of the application. The definition mechanism is a way
  9. # to place limits on that behavior. It allows you to protect a config entry, to specify the values it can take and to
  10. # validate it when it changes. In the next update it will also allow you to declare that
  11. # a config item is global or site-specific.
  12. #
  13. # The actual defining is done by TrustyCms::Config#define and usually in a block like this:
  14. #
  15. # TrustyCms::Config.prepare do |config|
  16. # config.namespace('users', :allow_change => true) do |users|
  17. # users.define 'allow_password_reset?', :label => 'Allow password reset?'
  18. # end
  19. # end
  20. #
  21. # See the method documentation in TrustyCms::Config for options and conventions.
  22. #
  23. def initialize(options = {})
  24. %i[empty default type notes validate_with select_from allow_blank allow_change allow_display units definer].each do |attribute|
  25. instance_variable_set "@#{attribute}".to_sym, options[attribute]
  26. end
  27. end
  28. # Returns true if the definition included an :empty flag, which should only be the case for the blank, unrestricting
  29. # definitions created when an undefined config item is set or got.
  30. #
  31. def empty?
  32. !!empty
  33. end
  34. # Returns true if the definition included a :type => :boolean parameter. Config entries that end in '?' are automatically
  35. # considered boolean, whether a type is declared or not. config.boolean? may therefore differ from config.definition.boolean?
  36. #
  37. def boolean?
  38. type == :boolean
  39. end
  40. # Returns true if the definition included a :select_from parameter (either as list or proc).
  41. #
  42. def selector?
  43. !select_from.blank?
  44. end
  45. # Returns true if the definition included a :type => :integer parameter
  46. def integer?
  47. type == :integer
  48. end
  49. # Returns the list of possible values for this config entry in a form suitable for passing to options_for_select.
  50. # if :select_from is a proc it is called first with no arguments and its return value passed through.
  51. #
  52. def selection
  53. if selector?
  54. choices = select_from
  55. choices = choices.call if choices.respond_to? :call
  56. choices = normalize_selection(choices)
  57. choices.unshift ['', ''] if allow_blank?
  58. choices
  59. end
  60. end
  61. # in definitions we accept anything that options_for_select would normally take
  62. # here we standardises on an options array-of-arrays so that it's easier to validate input
  63. #
  64. def normalize_selection(choices)
  65. choices = choices.to_a if Hash === choices
  66. choices = choices.collect { |c| (c.is_a? Array) ? c : [c, c] }
  67. end
  68. # If the config item is a selector and :select_from specifies [name, value] pairs (as hash or array),
  69. # this will return the name corresponding to the currently selected value.
  70. #
  71. def selected(value)
  72. if value && selector? && pair = selection.find { |s| s.last == value }
  73. pair.first
  74. end
  75. end
  76. # Checks the supplied value against the validation rules for this definition.
  77. # There are several ways in which validations might be defined or implied:
  78. # * if :validate_with specifies a block, the setting object is passed to the block
  79. # * if :type is :integer, we test that the supplied string resolves to a valid integer
  80. # * if the config item is a selector we test that its value is one of the permitted options
  81. # * if :allow_blank has been set to false, we test that the value is not blank
  82. #
  83. def validate(setting)
  84. if allow_blank?
  85. return if setting.value.blank?
  86. else
  87. setting.errors.add :value, :blank if setting.value.blank?
  88. end
  89. if validate_with.is_a? Proc
  90. validate_with.call(setting)
  91. end
  92. if selector?
  93. setting.errors.add :value, :not_permitted unless selectable?(setting.value)
  94. end
  95. if integer?
  96. begin
  97. Integer(setting.value)
  98. rescue StandardError
  99. setting.errors.add :value, :not_a_number
  100. end
  101. end
  102. end
  103. # Returns true if the value is one of the permitted selections. Not case-sensitive.
  104. def selectable?(value)
  105. return true unless selector?
  106. selection.map(&:last).map(&:downcase).include?(value.downcase)
  107. end
  108. # Returns true unless :allow_blank has been explicitly set to false. Defaults to true.
  109. # A config item that does not allow_blank must be set or it will not be valid.
  110. def allow_blank?
  111. true unless allow_blank == false
  112. end
  113. # Returns true unless :allow_change has been explicitly set to false. Defaults to true.
  114. # A config item that is not settable cannot be changed in the running application.
  115. def settable?
  116. true unless allow_change == false
  117. end
  118. # Returns true unless :allow_change has been explicitly set to false. Defaults to true.
  119. # A config item that is not visible cannot be displayed in a radius tag.
  120. def visible?
  121. true unless allow_display == false
  122. end
  123. # Returns true if :allow_display has been explicitly set to false. Defaults to true.
  124. def hidden?
  125. true if allow_display == false
  126. end
  127. end
  128. end
  129. end

lib/trusty_cms/deprecation.rb

0.0% lines covered

10 relevant lines. 0 lines covered and 10 lines missed.
    
  1. require 'active_support'
  2. class AssetType
  3. def paperclip_processors
  4. ActiveSupport::Deprecation.warn('Paperclip processors will be deprecated soon in favor of ActiveStorage.')
  5. active_storage_styles
  6. end
  7. def paperclip_styles
  8. ActiveSupport::Deprecation.warn('Paperclip styles will be deprecated soon in favor of ActiveStorage.')
  9. end
  10. end

lib/trusty_cms/engine.rb

0.0% lines covered

26 relevant lines. 0 lines covered and 26 lines missed.
    
  1. require 'ckeditor'
  2. require 'devise'
  3. require 'ransack'
  4. require 'paper_trail'
  5. require 'paper_trail-association_tracking'
  6. module TrustyCms
  7. class Engine < Rails::Engine
  8. isolate_namespace TrustyCms
  9. paths['app/helpers'] = []
  10. initializer 'trusty_cms.assets.precompile' do |app|
  11. app.config.assets.paths << Rails.root.join('../trusty-cms/node_modules')
  12. app.config.assets.precompile += %w(
  13. admin/main.css admin.js
  14. ckeditor/config.js
  15. ckeditor/contents.css
  16. ckeditor/config.js
  17. ckeditor/styles.js
  18. ckeditor/skins/moono/editor.css
  19. ckeditor/lang/en.js
  20. rad_social/rad_screen.css
  21. rad_social/rad_email.js
  22. rad_social/rad_widget.js
  23. )
  24. end
  25. end
  26. end

lib/trusty_cms/extension.rb

0.0% lines covered

105 relevant lines. 0 lines covered and 105 lines missed.
    
  1. require 'annotatable'
  2. require 'simpleton'
  3. require 'trusty_cms/admin_ui'
  4. module TrustyCms
  5. class Extension
  6. include Simpleton
  7. include Annotatable
  8. annotate :version, :description, :url, :extension_name, :path
  9. attr_writer :active
  10. def active?
  11. @active
  12. end
  13. def root
  14. path.to_s
  15. end
  16. def migrated?
  17. migrator.new(:up, migrations_path).pending_migrations.empty?
  18. end
  19. def enabled?
  20. active? and migrated?
  21. end
  22. # Conventional plugin-like routing
  23. def routed?
  24. File.exist?(routing_file)
  25. end
  26. def migrations_path
  27. File.join(root, 'db', 'migrate')
  28. end
  29. def migrates_from
  30. @migrates_from ||= {}
  31. end
  32. def routing_file
  33. File.join(root, 'config', 'routes.rb')
  34. end
  35. def load_initializers
  36. Dir["#{root}/config/initializers/**/*.rb"].sort.each do |initializer|
  37. require initializer
  38. end
  39. end
  40. def migrator
  41. unless @migrator
  42. extension = self
  43. @migrator = Class.new(ExtensionMigrator) { self.extension = extension }
  44. end
  45. @migrator
  46. end
  47. def admin
  48. AdminUI.instance
  49. end
  50. def tab(name, options = {}, &block)
  51. @the_tab = admin.nav[name]
  52. unless @the_tab
  53. @the_tab = TrustyCms::AdminUI::NavTab.new(name)
  54. before = options.delete(:before)
  55. after = options.delete(:after)
  56. tab_name = before || after
  57. tab_object = admin.nav[tab_name]
  58. if tab_object
  59. index = admin.nav.index(tab_object)
  60. index += 1 unless before
  61. admin.nav.insert(index, @the_tab)
  62. else
  63. admin.nav << @the_tab
  64. end
  65. end
  66. if block_given?
  67. block.call(@the_tab)
  68. end
  69. @the_tab
  70. end
  71. alias :add_tab :tab
  72. def add_item(*args)
  73. @the_tab.add_item(*args)
  74. end
  75. # Determine if another extension is installed and up to date.
  76. #
  77. # if MyExtension.extension_enabled?(:third_party)
  78. # ThirdPartyExtension.extend(MyExtension::IntegrationPoints)
  79. # end
  80. def extension_enabled?(extension)
  81. extension = (extension.to_s.camelcase + 'Extension').constantize
  82. extension.enabled?
  83. rescue NameError
  84. false
  85. end
  86. class << self
  87. def activate_extension
  88. return if instance.active?
  89. instance.activate_extension if instance.respond_to? :activate
  90. Dir["#{Rails.root}/config/routes/**/*.rb"].each do |route_file|
  91. end
  92. instance.active = true
  93. end
  94. def deactivate_extension
  95. return unless instance.active?
  96. instance.active = false
  97. instance.deactivate if instance.respond_to? :deactivate
  98. end
  99. alias :deactivate :deactivate_extension
  100. def inherited(subclass)
  101. subclass.extension_name = subclass.name.to_name('Extension')
  102. end
  103. def migrate_from(extension_name, until_migration = nil)
  104. instance.migrates_from[extension_name] = until_migration
  105. end
  106. def extension_config
  107. yield Rails.configuration
  108. end
  109. end
  110. end
  111. end

lib/trusty_cms/extension_loader.rb

0.0% lines covered

87 relevant lines. 0 lines covered and 87 lines missed.
    
  1. require 'trusty_cms/extension'
  2. require 'trusty_cms/extension_path'
  3. require 'method_observer'
  4. module TrustyCms
  5. class ExtensionLoader
  6. # The ExtensionLoader is reponsible for the loading, activation and reactivation of extensions.
  7. # The noticing of important subdirectories is now handled by the ExtensionPath class.
  8. class DependenciesObserver < MethodObserver
  9. # Extends the reload mechanism in ActiveSupport so that extensions are deactivated and reactivated
  10. # when model classes are reloaded (in development mode, usually).
  11. attr_accessor :config
  12. def initialize(rails_config)
  13. #:nodoc
  14. @config = rails_config
  15. end
  16. def before_clear(*_args)
  17. #:nodoc
  18. ExtensionLoader.deactivate_extensions
  19. end
  20. def after_clear(*_args)
  21. #:nodoc
  22. ExtensionLoader.load_extensions
  23. ExtensionLoader.activate_extensions
  24. end
  25. end
  26. include Simpleton
  27. attr_accessor :initializer, :extensions
  28. def initialize #:nodoc
  29. self.extensions = []
  30. end
  31. # Returns a list of paths to all the extensions that are enabled in the configuration of this application.
  32. #
  33. def enabled_extension_paths
  34. ExtensionPath.enabled.map(&:to_s)
  35. end
  36. # Returns a list of all the paths discovered within extension roots of the specified type.
  37. # (by calling the corresponding class method on ExtensionPath).
  38. #
  39. # extension_loader.paths(:metal) #=> ['extension/app/metal', 'extension/app/metal']
  40. # extension_loader.paths(:controller) #=> ['extension/app/controllers', 'extension/app/controllers']
  41. # extension_loader.paths(:eager_load) #=> ['extension/app/controllers', 'extension/app/models', 'extension/app/helpers']
  42. #
  43. # For compatibility with the old loader, there are corresponding +type_paths+ methods.
  44. # There are also (deprecated) +add_type_paths+ methods.
  45. #
  46. def paths(type)
  47. ExtensionPath.send("#{type}_paths".to_sym)
  48. end
  49. # Loads but does not activate all the extensions that have been enabled, in the configured order
  50. # (which defaults to alphabetically). If an extension fails to load an error will be logged
  51. # but application startup will continue. If an extension doesn't exist, a LoadError will be raised
  52. # and startup will halt.
  53. #
  54. def load_extensions
  55. configuration = TrustyCms::Application.config
  56. self.extensions = configuration.enabled_extensions.map { |ext| load_extension(ext) }.compact
  57. end
  58. # Loads the specified extension.
  59. #
  60. def load_extension(name)
  61. extension_path = ExtensionPath.find(name)
  62. begin
  63. constant = "#{name}_extension".camelize
  64. extension = constant.constantize
  65. extension.path = extension_path
  66. extension
  67. rescue LoadError, NameError => e
  68. warn "Could not load extension: #{name}.\n#{e.inspect}"
  69. nil
  70. end
  71. end
  72. # Loads all the initializers defined in enabled extensions, in the configured order.
  73. #
  74. def load_extension_initalizers
  75. extensions.each(&:load_initializers)
  76. end
  77. def load_extension_initializers
  78. load_extension_initalizers
  79. end
  80. # Deactivates all enabled extensions.
  81. #
  82. def deactivate_extensions
  83. extensions.each(&:deactivate)
  84. end
  85. # Activates all enabled extensions and makes sure that any newly declared subclasses of Page are recognised.
  86. # The admin UI and views have to be reinitialized each time to pick up changes and avoid duplicates.
  87. #
  88. def activate_extensions
  89. initializer.initialize_views
  90. ordered_extensions = []
  91. configuration = TrustyCms::Application.config
  92. if configuration.extensions.first == :all
  93. ordered_extensions = extensions
  94. else
  95. configuration.extensions.each { |name| ordered_extensions << select_extension(name) }
  96. end
  97. ordered_extensions.flatten.each(&:activate)
  98. Page.load_subclasses
  99. end
  100. def select_extension(name)
  101. extensions.select { |ext| ext.extension_name.symbolize == name }
  102. end
  103. alias :reactivate :activate_extensions
  104. class << self
  105. # Builds an ExtensionPath object from the supplied path, working out the name of the extension on the way.
  106. # The ExtensionPath object will later be used to scan and load the extension.
  107. # An extension name can be supplied in addition to the path. It will be processed in the usual way to
  108. # remove trusty- and -extension and any verion numbering.
  109. #
  110. def record_path(path, name = nil)
  111. ExtensionPath.from_path(path, name)
  112. end
  113. # For compatibility with old calls probably still to be found in some extensions.
  114. #
  115. %w{controller model view metal plugin load locale}.each do |type|
  116. define_method("#{type}_paths".to_sym) do
  117. paths(type)
  118. end
  119. define_method("add_#{type}_paths".to_sym) do |additional_paths|
  120. ::ActiveSupport::Deprecation.warn("ExtensionLoader.add_#{type}_paths is has been moved and is deprecated. Please use TrustyCms.configuration.add_#{type}_paths", caller)
  121. initializer.configuration.send("add_#{type}_paths".to_sym, additional_paths)
  122. end
  123. end
  124. end
  125. alias_method :load_extension_initializers, :load_extension_initalizers
  126. end
  127. end

lib/trusty_cms/extension_migrator.rb

0.0% lines covered

69 relevant lines. 0 lines covered and 69 lines missed.
    
  1. module TrustyCms
  2. class ExtensionMigrator < ActiveRecord::Migrator
  3. class << self
  4. attr_accessor :extension
  5. def migrate(target_version = nil)
  6. super extension.migrations_path, target_version
  7. end
  8. def migrate_extensions
  9. []
  10. end
  11. def get_all_versions
  12. ActiveRecord::Base.connection.select_values("SELECT version FROM #{sanitize(schema_migrations_table_name)}").
  13. select { |version| version.starts_with?("#{@extension.extension_name}-") }.
  14. map { |version| version.sub("#{@extension.extension_name}-", '').to_i }.sort
  15. end
  16. end
  17. def initialize(direction, migrations_path, target_version = nil)
  18. super
  19. initialize_extension_schema_migrations
  20. initialize_received_migrations
  21. end
  22. private
  23. def quote(s)
  24. ActiveRecord::Base.connection.quote(s)
  25. end
  26. def extension_name
  27. self.class.extension.extension_name
  28. end
  29. def version_string(version)
  30. "#{extension_name}-#{version}"
  31. end
  32. def initialize_extension_schema_migrations
  33. current_version = ActiveRecord::Base.connection.select_value("SELECT schema_version FROM extension_meta WHERE name = #{sanitize(quote(extension_name))}")
  34. if current_version
  35. assume_migrated_upto_version(current_version.to_i)
  36. ActiveRecord::Base.connection.delete("DELETE FROM extension_meta WHERE name = #{sanitize(quote(extension_name))}")
  37. end
  38. end
  39. def initialize_received_migrations
  40. if donors = self.class.extension.migrates_from
  41. donors.each do |extension_name, until_migration|
  42. replaced = ActiveRecord::Base.connection.select_values("SELECT version FROM #{sanitize(ActiveRecord::Migrator.schema_migrations_table_name)} WHERE version LIKE '#{extension_name}-%'").map { |v| v.sub(/^#{extension_name}\-/, '').to_i }
  43. replaced.delete_if { |v| v > until_migration.to_i } if until_migration
  44. assume_migrated_upto_version(replaced.max) if replaced.any?
  45. end
  46. end
  47. end
  48. def assume_migrated_upto_version(version)
  49. version = version.to_i
  50. sm_table = self.class.schema_migrations_table_name
  51. migrated = self.class.get_all_versions
  52. versions = Dir["#{@migrations_path}/[0-9]*_*.rb"].map do |filename|
  53. filename.split('/').last.split('_').first.to_i
  54. end
  55. unless migrated.include?(version)
  56. ActiveRecord::Base.connection.execute "INSERT INTO #{sm_table} (version) VALUES (#{sanitize(quote(version_string(version)))})"
  57. end
  58. inserted = Set.new
  59. (versions - migrated).each do |v|
  60. if inserted.include?(v)
  61. raise "Duplicate migration #{v}. Please renumber your migrations to resolve the conflict."
  62. elsif v < version
  63. ActiveRecord::Base.connection.execute "INSERT INTO #{sm_table} (version) VALUES (#{sanitize(quote(version_string(v)))})"
  64. inserted << v
  65. end
  66. end
  67. end
  68. end
  69. end

lib/trusty_cms/extension_path.rb

0.0% lines covered

90 relevant lines. 0 lines covered and 90 lines missed.
    
  1. module TrustyCms
  2. class ExtensionPath
  3. # This class holds information about extensions that may be loaded. It has two roles: to remember the
  4. # location of the extension so that we don't have to search for it again, and to look within that path
  5. # for significant application subdirectories.
  6. #
  7. # We can't just retrieve this information from the Extension class because the initializer sets up
  8. # most of the application load_paths before plugins (including extensions) are loaded. You can think
  9. # of this as a sort of pre-extension class preparing the way for extension loading.
  10. #
  11. # You can use instances of this class to retrieve information about a particular extension:
  12. #
  13. # ExtensionPath.new(:name, :path)
  14. # ExtensionPath.find(:name) #=> ExtensionPath instance
  15. # ExtensionPath.find(:name).plugin_paths #=> "path/vendor/plugins" if it exists and is a directory
  16. # ExtensionPath.for(:name) #=> "path"
  17. #
  18. # The initializer calls class methods to get overall lists (in configured order) of enabled load paths:
  19. #
  20. # ExtensionPath.enabled #=> ["path", "path", "path", "path"]
  21. # ExtensionPath.plugin_paths #=> ["path/vendor/plugins", "path/vendor/plugins"]
  22. attr_accessor :name, :path
  23. @@known_paths = {}
  24. def initialize(options = {}) #:nodoc
  25. @name = options[:name].underscore
  26. @path = options[:path]
  27. @@known_paths[@name.to_sym] = self
  28. end
  29. def required
  30. File.join(path, "#{name}_extension")
  31. end
  32. def to_s
  33. path
  34. end
  35. # Builds a new ExtensionPath object from the supplied path, working out the name of the extension by
  36. # stripping the extra bits from trusty-something-extension-1.0.0 to leave just 'something'. The object
  37. # is returned, and also remembered here for later use by the initializer (to find load paths) and the
  38. # ExtensionLoader, to load and activate the extension.
  39. #
  40. # If two arguments are given, the second is taken to be the full extension name.
  41. #
  42. def self.from_path(path, name = nil)
  43. name = path if name.blank?
  44. name = File.basename(name).gsub(/^trusty-|-extension(-[\d\.a-z]+|-[a-z\d]+)*$/, '')
  45. new(name: name, path: path)
  46. end
  47. # Forgets all recorded extension paths.
  48. # Currently only used in testing.
  49. #
  50. def self.clear_paths!
  51. @@known_paths = {}
  52. end
  53. # Returns a list of all the likely load paths found within this extension root. It includes all of these
  54. # that exist and are directories:
  55. #
  56. # * path
  57. # * path/lib
  58. # * path/app/models
  59. # * path/app/controllers
  60. # * path/app/metal
  61. # * path/app/helpers
  62. # * path/test/helpers
  63. #
  64. # You can call the class method ExtensionPath.load_paths to get a flattened list of all the load paths in all the enabled extensions.
  65. #
  66. def load_paths
  67. %w(lib app/models app/controllers app/metal app/helpers test/helpers).collect { |d| check_subdirectory(d) }.push(path).flatten.compact
  68. end
  69. # Returns a list of all the +vendor/plugin+ paths found within this extension root.
  70. # Call the class method ExtensionPath.plugin_paths to get a list of the plugin paths found in all enabled extensions.
  71. #
  72. def plugin_paths
  73. check_subdirectory('vendor/plugins')
  74. end
  75. # Returns a list of names of all the locale files found within this extension root.
  76. # Call the class method ExtensionPath.locale_paths to get a list of the locale files found in all enabled extensions
  77. # in reverse order so that locale definitions override one another correctly.
  78. #
  79. def locale_paths
  80. if check_subdirectory('config/locales')
  81. Dir[File.join(path.to_s, 'config/locales', '*.{rb,yml}')]
  82. end
  83. end
  84. # Returns the app/helpers path if it is found within this extension root.
  85. # Call the class method ExtensionPath.helper_paths to get a list of the helper paths found in all enabled extensions.
  86. #
  87. def helper_paths
  88. check_subdirectory('app/helpers')
  89. end
  90. # Returns the app/models path if it is found within this extension root.
  91. # Call the class method ExtensionPath.model_paths to get a list of the model paths found in all enabled extensions.
  92. #
  93. def model_paths
  94. check_subdirectory('app/models')
  95. end
  96. # Returns the app/controllers path if it is found within this extension root.
  97. # Call the class method ExtensionPath.controller_paths to get a list of the controller paths found in all enabled extensions.
  98. #
  99. def controller_paths
  100. check_subdirectory('app/controllers')
  101. end
  102. # Returns the app/views path if it is found within this extension root.
  103. # Call the class method ExtensionPath.view_paths to get a list of the view paths found in all enabled extensions
  104. # in reverse order so that views override one another correctly.
  105. #
  106. def view_paths
  107. check_subdirectory('app/views')
  108. end
  109. # Returns the app/metal path if it is found within this extension root.
  110. # Call the class method ExtensionPath.metal_paths to get a list of the metal paths found in all enabled extensions.
  111. #
  112. def metal_paths
  113. check_subdirectory('app/metal')
  114. end
  115. # Returns a list of all the rake task files found within this extension root.
  116. #
  117. def rake_task_paths
  118. if check_subdirectory('lib/tasks')
  119. Dir[File.join(path.to_s, 'lib/tasks/**', '*.rake')]
  120. end
  121. end
  122. # Returns a list of extension subdirectories that should be marked for eager loading. At the moment that
  123. # includes all the controller, model and helper paths. The main purpose here is to ensure that extension
  124. # controllers are loaded before running cucumber features, and there may be a better way to achieve that.
  125. #
  126. # Call the class method ExtensionPath.eager_load_paths to get a list for all enabled extensions.
  127. #
  128. def eager_load_paths
  129. [controller_paths, model_paths, helper_paths].flatten.compact
  130. end
  131. class << self
  132. # Returns the ExtensionPath object for the given extension name.
  133. #
  134. def find(name)
  135. raise LoadError, "Cannot return path for unknown extension: #{name}" unless @@known_paths[name.to_sym]
  136. @@known_paths[name.to_sym]
  137. end
  138. # Returns the root path recorded for the given extension name.
  139. #
  140. def for(name)
  141. find(name).path
  142. end
  143. # Returns a list of path objects for all the enabled extensions in the configured order.
  144. # If a configured extension has not been found during initialization, a LoadError will be thrown here.
  145. #
  146. # Note that at this stage, in line with the usage of config.extensions = [], the extension names
  147. # are being passed around as symbols.
  148. #
  149. def enabled
  150. enabled_extensions = TrustyCms::Application.config.enabled_extensions
  151. @@known_paths.values_at(*enabled_extensions).compact
  152. end
  153. # Returns a list of the root paths to all the enabled extensions, in the configured order.
  154. #
  155. def enabled_paths
  156. enabled.map(&:path)
  157. end
  158. %i[load_paths plugin_paths helper_paths model_paths controller_paths eager_load_paths].each do |m|
  159. define_method(m) do
  160. enabled.map { |ep| ep.send(m) }.flatten.compact
  161. end
  162. end
  163. %i[locale_paths view_paths metal_paths rake_task_paths].each do |m|
  164. define_method(m) do
  165. enabled.map { |ep| ep.send(m) }.flatten.compact.reverse
  166. end
  167. end
  168. end
  169. private
  170. # If the supplied path within the extension root exists and is a directory, its absolute path is returned. Otherwise, nil.
  171. #
  172. def check_subdirectory(subpath)
  173. subdirectory = File.join(path, subpath)
  174. subdirectory if File.directory?(subdirectory)
  175. end
  176. end
  177. end

lib/trusty_cms/initializer.rb

0.0% lines covered

76 relevant lines. 0 lines covered and 76 lines missed.
    
  1. require 'will_paginate'
  2. require 'rails'
  3. require 'haml-rails'
  4. require 'haml'
  5. require 'mysql2'
  6. require 'trusty_cms/admin_ui'
  7. require 'trusty_cms/extension_loader'
  8. require 'string_extensions/string_extensions'
  9. require 'trusty_cms/engine'
  10. module TrustyCms
  11. module Initializer
  12. # Rails::Initializer is essentially a list of startup steps and we extend it here by:
  13. # * overriding or extending some of those steps so that they use trusty and extension paths
  14. # as well as (or instead of) the rails defaults.
  15. # * appending some extra steps to set up the admin UI and activate extensions
  16. # Returns true in the very unusual case where trusty has been deployed as a rails app itself, rather than
  17. # loaded as a gem or from vendor/. This is only likely in situations where trusty is customised so heavily
  18. # that extensions are not sufficient.
  19. #
  20. def deployed_as_app?
  21. TRUSTY_CMS_ROOT == Rails.root
  22. end
  23. # Extends the Rails::Initializer default to add extension paths to the autoload list.
  24. # Note that +default_autoload_paths+ is also overridden to point to TRUSTY_CMS_ROOT.
  25. #
  26. def set_autoload_patf
  27. super
  28. end
  29. # Overrides the Rails initializer to load metal from TRUSTY_CMS_ROOT and from trusty extensions.
  30. #
  31. def initialize_metal
  32. Rails::Rack::Metal.requested_metals = configuration.metals
  33. Rails::Rack::Metal.metal_paths = ["#{TRUSTY_CMS_ROOT}/app/metal"] # reset Rails default to TRUSTY_CMS_ROOT
  34. Rails::Rack::Metal.metal_paths += plugin_loader.engine_metal_paths
  35. Rails::Rack::Metal.metal_paths += extension_loader.paths(:metal)
  36. Rails::Rack::Metal.metal_paths.uniq!
  37. configuration.middleware.insert_before(
  38. :"ActionController::ParamsParser",
  39. Rails::Rack::Metal, if: Rails::Rack::Metal.metals.any?
  40. )
  41. end
  42. # Extends the Rails initializer to add locale paths from TRUSTY_CMS_ROOT and from trusty extensions.
  43. #
  44. def initialize_i18n
  45. trusty_locale_paths = Dir[File.join(TRUSTY_CMS_ROOT, 'config', 'locales', '*.{rb,yml}')]
  46. configuration.i18n.load_path = trusty_locale_paths + extension_loader.paths(:locale)
  47. super
  48. end
  49. # Extends the Rails initializer to add plugin paths in extensions
  50. # and makes extension load paths reloadable (eg in development mode)
  51. # ActiveSupport::Dependencies has been deprecated. We imported all the gems a long
  52. # time ago. This is a relic of the past. We should remove it and any references to plugins/gems in the future.
  53. # def add_plugin_load_paths
  54. # configuration.add_plugin_paths(extension_loader.paths(:plugin))
  55. # super
  56. # ActiveSupport::Dependencies.autoload_once_paths -= extension_loader.paths(:load)
  57. # end
  58. # Overrides the standard gem-loader to use Bundler instead of config.gem. This is the method normally monkey-patched
  59. # into Rails::Initializer from boot.rb if you follow the instructions at http://gembundler.com/rails23.html
  60. #
  61. def load_gems
  62. @bundler_loaded ||= Bundler.require :default, Rails.env
  63. end
  64. # Extends the Rails initializer also to load trusty extensions (which have been excluded from the list of plugins).
  65. #
  66. def load_plugins
  67. super
  68. extension_loader.load_extensions
  69. end
  70. # Extends the Rails initializer to run initializers from trusty and from extensions. The load order will be:
  71. # 1. TRUSTY_CMS_ROOT/config/intializers/*.rb
  72. # 2. Rails.root/config/intializers/*.rb
  73. # 3. config/initializers/*.rb found in extensions, in extension load order.
  74. #
  75. # In the now rare case where trusty is deployed as an ordinary rails application, step 1 is skipped
  76. # because it is equivalent to step 2.
  77. #
  78. def load_application_initializers
  79. load_trusty_initializers unless deployed_as_app?
  80. super
  81. extension_loader.load_extension_initializers
  82. end
  83. # Loads initializers found in TRUSTY_CMS_ROOT/config/initializers.
  84. #
  85. def load_trusty_initializers
  86. Dir["#{TRUSTY_CMS_ROOT}/config/initializers/**/*.rb"].sort.each do |initializer|
  87. load(initializer)
  88. end
  89. end
  90. # Extends the Rails initializer with some extra steps at the end of initialization:
  91. # * hook up trusty view paths in controllers and notifiers
  92. # * initialize the navigation tabs in the admin interface
  93. # * initialize the extendable partial sets that make up the admin interface
  94. # * call +activate+ on all trusty extensions
  95. # * add extension controller paths
  96. # * mark extension app paths for eager loading
  97. #
  98. def after_initialize
  99. super
  100. extension_loader.activate_extensions # also calls initialize_views
  101. TrustyCms::Application.config.add_controller_paths(extension_loader.paths(:controller))
  102. TrustyCms::Application.config.add_eager_load_paths(extension_loader.paths(:eager_load))
  103. end
  104. # Initializes all the admin interface elements and views. Separate here so that it can be called
  105. # to reset the interface before extension (re)activation.
  106. #
  107. def initialize_views
  108. initialize_default_admin_tabs
  109. admin.load_default_regions
  110. end
  111. # Initializes the core admin tabs. Separate so that it can be invoked by itself in tests.
  112. #
  113. def initialize_default_admin_tabs
  114. admin.initialize_nav
  115. end
  116. # Extends the Rails initializer to make sure that extension controller paths are available when routes
  117. # are initialized.
  118. #
  119. def initialize_routing
  120. configuration.add_controller_paths(extension_loader.paths(:controller))
  121. configuration.add_eager_load_paths(extension_loader.paths(:eager_load))
  122. super
  123. end
  124. # Returns the TrustyCms::AdminUI singleton so that the initializer can set up the admin interface.
  125. #
  126. def admin
  127. TrustyCms::Application.config.admin
  128. end
  129. # Returns the ExtensionLoader singleton that will eventually load extensions.
  130. #
  131. def extension_loader
  132. ExtensionLoader.instance { |l| l.initializer = self }
  133. end
  134. end
  135. end

lib/trusty_cms/pagination/controller.rb

0.0% lines covered

25 relevant lines. 0 lines covered and 25 lines missed.
    
  1. module TrustyCms
  2. module Pagination
  3. module Controller
  4. # for inclusion into public-facing controllers
  5. def configure_pagination
  6. # unconfigured parameters remain at will_paginate defaults
  7. # will_paginate controller options are not overridden by tag attribetus
  8. WillPaginate::ViewHelpers.pagination_options[:param_name] = TrustyCms::Config['pagination.param_name'].to_sym unless TrustyCms::Config['pagination.param_name'].blank?
  9. WillPaginate::ViewHelpers.pagination_options[:per_page_param_name] = TrustyCms::Config['pagination.per_page_param_name'].blank? ? :per_page : TrustyCms::Config['pagination.per_page_param_name'].to_sym
  10. # will_paginate view options can be overridden by tag attributes
  11. %i[class previous_label next_label inner_window outer_window separator container].each do |opt|
  12. WillPaginate::ViewHelpers.pagination_options[opt] = TrustyCms::Config["pagination.#{opt}"] unless TrustyCms::Config["pagination.#{opt}"].blank?
  13. end
  14. end
  15. def pagination_parameters
  16. {
  17. page: params[WillPaginate::ViewHelpers.pagination_options[:param_name]] || 1,
  18. per_page: params[WillPaginate::ViewHelpers.pagination_options[:per_page_param_name]] || TrustyCms::Config['pagination.per_page'] || 20,
  19. }
  20. end
  21. def self.included(base)
  22. base.class_eval do
  23. helper_method :pagination_parameters
  24. before_action :configure_pagination
  25. end
  26. end
  27. end
  28. end
  29. end

lib/trusty_cms/pagination/link_renderer.rb

0.0% lines covered

25 relevant lines. 0 lines covered and 25 lines missed.
    
  1. # This handy simplification is adapted from SphinxSearch (thanks)
  2. # and originally came from Ultrasphinx
  3. # it saves us a lot of including and bodging to make will_paginate's template calls work in the Page model
  4. module TrustyCms
  5. module Pagination
  6. class LinkRenderer < WillPaginate::LinkRenderer
  7. def initialize(url_stem)
  8. @url_stem = url_stem
  9. end
  10. def to_html
  11. links = @options[:page_links] ? windowed_links : []
  12. links.unshift page_link_or_span(@collection.previous_page, 'disabled prev_page', @options[:previous_label])
  13. links.push page_link_or_span(@collection.next_page, 'disabled next_page', @options[:next_label])
  14. html = links.join(@options[:separator])
  15. @options[:container] ? %{<div class="pagination">#{html}</div>} : html
  16. end
  17. # this is rather crude compared to the WillPaginate link-builder,
  18. # but it can get by without much context to draw on
  19. def page_link(page, text, attributes = {})
  20. linkclass = %{ class="#{attributes[:class]}"} if attributes[:class]
  21. linkrel = %{ rel="#{attributes[:rel]}"} if attributes[:rel]
  22. param_name = WillPaginate::ViewHelpers.pagination_options[:param_name]
  23. %{<a href="#{@url_stem}?#{param_name}=#{page}"#{linkrel}#{linkclass}>#{text}</a>}
  24. end
  25. def page_span(_page, text, attributes = {})
  26. %{<span class="#{attributes[:class]}">#{text}</span>}
  27. end
  28. end
  29. end
  30. end

lib/trusty_cms/resource_responses.rb

0.0% lines covered

105 relevant lines. 0 lines covered and 105 lines missed.
    
  1. require 'ostruct'
  2. module TrustyCms
  3. module ResourceResponses
  4. def self.extended(base)
  5. base.send :class_attribute, :responses
  6. base.send :include, InstanceMethods
  7. end
  8. def create_responses
  9. r = (self.responses ||= Collector.new)
  10. yield r if block_given?
  11. r
  12. end
  13. module InstanceMethods
  14. def response_for(action)
  15. responses = self.class.responses.send(action)
  16. respond_to do |wants|
  17. responses.each_format do |f, format_block|
  18. if format_block
  19. wants.send(f, &wrap(format_block))
  20. else
  21. wants.send(f)
  22. end
  23. end
  24. responses.each_published do |pub, pub_block|
  25. wants.send(pub, &wrap(pub_block))
  26. end
  27. if responses.default
  28. wants.any(&wrap(responses.default))
  29. else
  30. wants.any
  31. end
  32. end
  33. end
  34. def wrap(proc)
  35. # Makes sure our response blocks get evaluated in the right context
  36. lambda do
  37. # Ruby 1.9.2 yields self in instance_eval... see https://gist.github.com/479572
  38. # lambdas are as strict as methods in 1.9.x, making sure that the args match, Procs are not.
  39. if RUBY_VERSION =~ /^1\.9/ && proc.lambda? && (proc.arity != 1)
  40. raise "You can only pass a proc ('Proc.new') or a lambda that takes exactly one arg (for self) to the wrap method."
  41. end
  42. instance_eval(&proc)
  43. end
  44. end
  45. end
  46. class Collector < OpenStruct
  47. def initialize
  48. super
  49. @table = Hash.new { |h, k| h[k] = Response.new }
  50. end
  51. def initialize_copy(orig)
  52. super
  53. @table.keys.each do |key|
  54. @table[key] = orig.send(key).dup
  55. end
  56. end
  57. end
  58. class Response
  59. attr_reader :publish_formats, :publish_block, :blocks, :block_order
  60. def initialize
  61. @publish_formats = []
  62. @blocks = {}
  63. @block_order = []
  64. end
  65. def initialize_copy(orig)
  66. @publish_formats = orig.publish_formats.dup
  67. @blocks = orig.blocks.dup
  68. @block_order = orig.block_order.dup
  69. @publish_block = orig.publish_block.dup if orig.publish_block
  70. @default = orig.default.dup if orig.default
  71. end
  72. def default(&block)
  73. if block_given?
  74. @default = block
  75. end
  76. @default
  77. end
  78. def publish(*formats, &block)
  79. @publish_formats.concat(formats)
  80. if block_given?
  81. @publish_block = block
  82. else
  83. raise ArgumentError, 'Block required to publish' unless @publish_block
  84. end
  85. end
  86. def each_published
  87. publish_formats.each do |format|
  88. yield format, publish_block if block_given?
  89. end
  90. end
  91. def each_format
  92. @block_order.each do |format|
  93. yield format, @blocks[format] if block_given?
  94. end
  95. end
  96. def method_missing(method, *args, &block)
  97. if block_given?
  98. @blocks[method] = block
  99. @block_order << method unless @block_order.include?(method)
  100. elsif args.empty?
  101. @block_order << method
  102. else
  103. super
  104. end
  105. end
  106. end
  107. end
  108. end

lib/trusty_cms/setup.rb

0.0% lines covered

200 relevant lines. 0 lines covered and 200 lines missed.
    
  1. require 'highline'
  2. require 'forwardable'
  3. module TrustyCms
  4. class Setup
  5. class << self
  6. def bootstrap(config)
  7. setup = new
  8. setup.bootstrap(config)
  9. setup
  10. end
  11. end
  12. attr_accessor :config
  13. def bootstrap(config)
  14. @config = config
  15. @admin = create_admin_user(config[:admin_name], config[:admin_username], config[:admin_password])
  16. load_default_configuration
  17. # load_database_template(config[:database_template])
  18. announce 'Finished.'
  19. end
  20. def create_admin_user(name, username, password)
  21. unless name && username && password
  22. announce 'Create the admin user (press enter for defaults).'
  23. name ||= prompt_for_admin_name
  24. username ||= prompt_for_admin_username
  25. password ||= prompt_for_admin_password
  26. end
  27. attributes = {
  28. first_name: name,
  29. email: username,
  30. password: password,
  31. password_confirmation: password,
  32. }
  33. admin = User.find_by(email: username)
  34. admin ||= User.new
  35. admin.update(attributes)
  36. admin.admin = true
  37. admin.save!
  38. admin
  39. end
  40. def load_default_configuration
  41. feedback "\nInitializing configuration" do
  42. step { TrustyCms::Config['admin.title'] = 'TrustyCms CMS' }
  43. step { TrustyCms::Config['admin.subtitle'] = 'Publishing for Small Teams' }
  44. step { TrustyCms::Config['defaults.page.parts'] = 'body, extended' }
  45. step { TrustyCms::Config['defaults.page.status'] = 'Draft' }
  46. step { TrustyCms::Config['defaults.page.filter'] = nil }
  47. step { TrustyCms::Config['defaults.page.fields'] = 'Keywords, Description' }
  48. step { TrustyCms::Config['session_timeout'] = 2.weeks }
  49. step { TrustyCms::Config['default_locale'] = 'en' }
  50. end
  51. end
  52. def load_database_template(filename)
  53. template = nil
  54. if filename
  55. name = find_template_in_path(filename)
  56. if name
  57. template = load_template_file(name)
  58. else
  59. announce "Invalid template name: #{filename}"
  60. filename = nil
  61. end
  62. end
  63. unless filename
  64. templates = find_and_load_templates("#{TRUSTY_CMS_ROOT}/db/templates/*.yml")
  65. templates.concat find_and_load_templates("#{TRUSTY_CMS_ROOT}/vendor/extensions/**/db/templates/*.yml")
  66. TrustyCms::Extension.descendants.each do |d|
  67. templates.concat find_and_load_templates(d.root + '/db/templates/*.yml')
  68. end
  69. templates.concat find_and_load_templates("#{Rails.root}/vendor/extensions/**/db/templates/*.yml")
  70. templates.concat find_and_load_templates("#{Rails.root}/db/templates/*.yml")
  71. templates.uniq!
  72. choose do |menu|
  73. menu.header = "\nSelect a database template"
  74. menu.prompt = "[1-#{templates.size}]: "
  75. menu.select_by = :index
  76. templates.each { |t| menu.choice(t['name']) { template = t } }
  77. end
  78. end
  79. create_records(template)
  80. end
  81. private
  82. def prompt_for_admin_name
  83. username = ask('Name (Administrator): ', String) do |q|
  84. q.validate = /^.{0,100}$/
  85. q.responses[:not_valid] = 'Invalid name. Must be under 100 characters long.'
  86. q.whitespace = :strip
  87. end
  88. username = 'Administrator' if username.blank?
  89. username
  90. end
  91. def prompt_for_admin_username
  92. username = ask('Username (admin@trustarts.org): ', String) do |q|
  93. q.validate = /^(|.{3,40})$/
  94. q.responses[:not_valid] = 'Invalid username. Must be at least 3 characters long.'
  95. q.whitespace = :strip
  96. end
  97. username = 'admin@trustarts.org' if username.blank?
  98. username
  99. end
  100. def prompt_for_admin_password
  101. default_password = 'Trusty123456@!'
  102. password = ask("Password (#{default_password}): ", String) do |q|
  103. q.echo = false unless defined?(::JRuby) # JRuby doesn't support stty interaction
  104. q.validate = /^(|.{5,40})$/
  105. q.responses[:not_valid] = 'Invalid password. Must be at least 5 characters long.'
  106. q.whitespace = :strip
  107. end
  108. password = default_password if password.blank?
  109. password
  110. end
  111. def find_template_in_path(filename)
  112. (
  113. [
  114. filename,
  115. "#{TRUSTY_CMS_ROOT}/#{filename}",
  116. "#{TRUSTY_CMS_ROOT}/db/templates/#{filename}",
  117. "#{Rails.root}/#{filename}",
  118. "#{Rails.root}/db/templates/#{filename}",
  119. "#{Dir.pwd}/#{filename}",
  120. "#{Dir.pwd}/db/templates/#{filename}",
  121. ] +
  122. Dir.glob("#{TRUSTY_CMS_ROOT}/vendor/extensions/**/db/templates/#{filename}") +
  123. Dir.glob("#{Rails.root}/vendor/extensions/**/db/templates/#{filename}") +
  124. TrustyCms::Extension.descendants.inject([]) do |r, d|
  125. r << "#{d.root}/db/templates/#{filename}"
  126. end
  127. ).find { |name| File.file?(name) }
  128. end
  129. def find_and_load_templates(glob)
  130. templates = Dir[glob]
  131. templates.map! { |template| load_template_file(template) }
  132. templates.sort_by { |template| template['name'] }
  133. end
  134. def load_template_file(filename)
  135. YAML.load_file(filename)
  136. end
  137. def create_records(template)
  138. records = template['records']
  139. if records
  140. puts
  141. records.keys.each do |key|
  142. feedback "Creating #{key.to_s.underscore.humanize}" do
  143. model = model(key)
  144. model.reset_column_information
  145. record_pairs = order_by_id(records[key])
  146. step do
  147. record_pairs.each do |_id, record|
  148. model.new(record).save
  149. end
  150. end
  151. end
  152. end
  153. end
  154. end
  155. def model(model_name)
  156. model_name.to_s.singularize.constantize
  157. end
  158. def order_by_id(records)
  159. records.map { |_name, record| [record['id'], record] }.sort { |a, b| a[0] <=> b[0] }
  160. end
  161. extend Forwardable
  162. def_delegators :terminal, :agree, :ask, :choose, :say
  163. def terminal
  164. @terminal ||= HighLine.new
  165. end
  166. def output
  167. terminal.instance_variable_get('@output')
  168. end
  169. def wrap(string)
  170. string = terminal.send(:wrap, string) unless terminal.wrap_at.nil?
  171. string
  172. end
  173. def print(string)
  174. output.print(wrap(string))
  175. output.flush
  176. end
  177. def puts(string = "\n")
  178. say string
  179. end
  180. def announce(string)
  181. puts "\n#{string}"
  182. end
  183. def feedback(process)
  184. print "#{process}..."
  185. if yield
  186. puts 'OK'
  187. true
  188. else
  189. puts 'FAILED'
  190. false
  191. end
  192. rescue Exception => e
  193. puts 'FAILED'
  194. raise e
  195. end
  196. def step
  197. yield if block_given?
  198. print '.'
  199. end
  200. end
  201. end

lib/trusty_cms/taggable.rb

0.0% lines covered

100 relevant lines. 0 lines covered and 100 lines missed.
    
  1. module TrustyCms::Taggable
  2. mattr_accessor :last_description, :tag_descriptions, :tag_deprecations
  3. @@tag_descriptions = {}
  4. @@tag_deprecations = {}
  5. def self.included(base)
  6. base.extend(ClassMethods)
  7. base.module_eval do
  8. def self.included(new_base)
  9. super
  10. new_base.class_eval do
  11. include Rails.application.routes.url_helpers
  12. end
  13. class << new_base
  14. def default_url_options
  15. { controller: 'site', action: 'show_page', only_path: true }
  16. end
  17. end
  18. new_base.tag_descriptions.merge! tag_descriptions
  19. end
  20. protected
  21. def params
  22. @params ||= request.parameters unless request.nil?
  23. end
  24. def request_uri
  25. @request_url ||= request.request_uri unless request.nil?
  26. end
  27. end
  28. end
  29. def render_tag(name, tag_binding)
  30. tag_method_name = "tag:#{name}"
  31. tag_method = method(tag_method_name)
  32. if tag_method.arity == 0
  33. tag_method.call
  34. else
  35. tag_method.call tag_binding
  36. end
  37. end
  38. def tags
  39. Util.tags_in_array(methods)
  40. end
  41. def tag_descriptions(hash = nil)
  42. self.class.tag_descriptions hash
  43. end
  44. def warn_of_tag_deprecation(tag_name, options = {})
  45. message = "Deprecated radius tag <r:#{tag_name}>"
  46. message << " will be removed or significantly changed in trusty #{options[:deadline]}." if options[:deadline]
  47. message << " Please use <r:#{options[:substitute]}> instead." if options[:substitute]
  48. ActiveSupport::Deprecation.warn(message)
  49. end
  50. module ClassMethods
  51. def inherited(subclass)
  52. subclass.tag_descriptions.reverse_merge! tag_descriptions
  53. super
  54. end
  55. def tag_descriptions(hash = nil)
  56. TrustyCms::Taggable.tag_descriptions[name] ||= (hash || {})
  57. end
  58. def desc(text)
  59. TrustyCms::Taggable.last_description = text
  60. # TrustyCms::Taggable.last_description = RedCloth.new(Util.strip_leading_whitespace(text)).to_html
  61. end
  62. def tag(name, &block)
  63. tag_descriptions[name] = TrustyCms::Taggable.last_description if TrustyCms::Taggable.last_description
  64. TrustyCms::Taggable.last_description = nil
  65. define_method("tag:#{name}", &block)
  66. end
  67. def tags
  68. Util.tags_in_array(instance_methods)
  69. end
  70. # Define a tag while also deprecating it. Normal usage:
  71. #
  72. # deprecated_tag 'old:way', :substitute => 'new:way', :deadline => '1.1.1'
  73. #
  74. # If no substitute is given then a warning will be issued but nothing rendered.
  75. # If a deadline version is provided then it will be mentioned in the deprecation warnings.
  76. #
  77. # In less standard situations you can use deprecated_tag in exactly the
  78. # same way as tags are normally defined:
  79. #
  80. # desc %{
  81. # Please note that the old r:busted namespace is no longer supported.
  82. # Refer to the documentation for more about the new r:hotness tags.
  83. # }
  84. # deprecated_tag 'busted' do |tag|
  85. # raise TagError "..."
  86. # end
  87. #
  88. def deprecated_tag(name, options = {}, &dblock)
  89. TrustyCms::Taggable.tag_deprecations[name] = options.dup
  90. if dblock
  91. tag(name) do |tag|
  92. warn_of_tag_deprecation(name, options)
  93. dblock.call(tag)
  94. end
  95. else
  96. tag(name) do |tag|
  97. warn_of_tag_deprecation(name, options)
  98. tag.render(options[:substitute], tag.attr.dup, &tag.block) if options[:substitute]
  99. end
  100. end
  101. end
  102. end
  103. module Util
  104. def self.tags_in_array(array)
  105. array.grep(/^tag:/).map { |name| name[4..-1] }.sort
  106. end
  107. def self.strip_leading_whitespace(text)
  108. text = text.dup
  109. text.gsub!("\t", ' ')
  110. lines = text.split("\n")
  111. leading = lines.map do |line|
  112. unless line =~ /^\s*$/
  113. line.match(/^(\s*)/)[0].length
  114. end
  115. end.compact.min
  116. lines.inject([]) { |ary, line| ary << line.sub(/^[ ]{#{leading}}/, '') }.join("\n")
  117. end
  118. end
  119. end

lib/trusty_cms/task_support.rb

0.0% lines covered

59 relevant lines. 0 lines covered and 59 lines missed.
    
  1. module TrustyCms
  2. class TaskSupport
  3. class << self
  4. def establish_connection
  5. unless ActiveRecord::Base.connected?
  6. connection_hash = YAML.load_file("#{Rails.root}/config/database.yml").to_hash
  7. env_connection = connection_hash[Rails.env]
  8. ActiveRecord::Base.establish_connection(env_connection)
  9. end
  10. end
  11. def config_export(path = "#{Rails.root}/config/trusty_config.yml")
  12. establish_connection
  13. FileUtils.mkdir_p(File.dirname(path))
  14. if File.open(File.expand_path(path), 'w') { |f| YAML.dump(TrustyCms::Config.to_hash.to_yaml, f) }
  15. puts "TrustyCms::Config saved to #{path}"
  16. end
  17. end
  18. def config_import(path = "#{Rails.root}/config/trusty_config.yml", clear = nil)
  19. establish_connection
  20. if File.exist?(path)
  21. begin
  22. TrustyCms::Config.transaction do
  23. TrustyCms::Config.delete_all if clear
  24. configs = YAML.load(YAML.load_file(path))
  25. configs.each do |key, value|
  26. c = TrustyCms::Config.find_or_initialize_by_key(key)
  27. c.value = value
  28. c.save
  29. end
  30. end
  31. puts "TrustyCms::Config updated from #{path}"
  32. rescue ActiveRecord::RecordInvalid => e
  33. puts "IMPORT FAILED and rolled back. #{e}"
  34. end
  35. else
  36. puts "No file exists at #{path}"
  37. end
  38. end
  39. # Write the combined content of files in dir into cache_file in the same dir.
  40. #
  41. def cache_files(dir, files, cache_file)
  42. cache_content = files.collect do |f|
  43. File.read(File.join(dir, f))
  44. end.join("\n\n")
  45. cache_path = File.join(dir, cache_file)
  46. File.delete(cache_path) if File.exist?(cache_path)
  47. File.open(cache_path, 'w+') { |f| f.write(cache_content) }
  48. end
  49. # Reads through the layout file and returns an array of JS filenames
  50. #
  51. def find_admin_js
  52. layout = "#{TRUSTY_CMS_ROOT}/app/views/layouts/application"
  53. js_regexp = /javascript_include_tag %w\((.*)\), :cache => 'admin\/all/
  54. files = File.open(layout) { |f| f.read.match(js_regexp)[1].split }
  55. files.collect { |f| f.split('/').last + '.js' }
  56. end
  57. def cache_admin_js
  58. dir = "#{Rails.root}/public/javascripts/admin"
  59. cache_files(dir, find_admin_js, 'all.js')
  60. end
  61. end
  62. end
  63. end

lib/trusty_cms/version.rb

0.0% lines covered

3 relevant lines. 0 lines covered and 3 lines missed.
    
  1. module TrustyCms
  2. VERSION = '7.0.9'.freeze
  3. end