camaleon_cms 2.9.2 → 2.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -4
  3. data/Rakefile +3 -16
  4. data/app/apps/plugins/attack/admin_controller.rb +9 -6
  5. data/app/apps/plugins/attack/attack_helper.rb +35 -25
  6. data/app/apps/plugins/authoring_post/authoring_post_helper.rb +23 -16
  7. data/app/apps/plugins/front_cache/admin_controller.rb +14 -10
  8. data/app/apps/plugins/front_cache/config/initializer.rb +1 -1
  9. data/app/apps/plugins/front_cache/config/locales/translation.yml +0 -7
  10. data/app/apps/plugins/front_cache/front_cache_helper.rb +109 -37
  11. data/app/apps/plugins/front_cache/views/admin/settings.html.erb +0 -5
  12. data/app/apps/plugins/visibility_post/config/config.json +1 -0
  13. data/app/apps/plugins/visibility_post/config/routes_front.txt +1 -0
  14. data/app/apps/plugins/visibility_post/front_controller.rb +23 -0
  15. data/app/apps/plugins/visibility_post/visibility_post_helper.rb +141 -70
  16. data/app/apps/themes/camaleon_first/main_helper.rb +18 -12
  17. data/app/apps/themes/default/assets/css/style.css.scss +24 -0
  18. data/app/apps/themes/default/assets/genericons/genericons.css +3 -8
  19. data/app/apps/themes/default/default_helper.rb +2 -1
  20. data/app/apps/themes/default/views/layouts/index.html.erb +3 -1
  21. data/app/apps/themes/new/assets/css/styles.css.scss +24 -0
  22. data/app/apps/themes/new/custom_helper.rb +5 -9
  23. data/app/apps/themes/new/views/layouts/_header.html.erb +3 -1
  24. data/app/assets/javascripts/camaleon_cms/admin/_data.js +16 -0
  25. data/app/assets/javascripts/camaleon_cms/admin/_post.js +5 -2
  26. data/app/assets/javascripts/camaleon_cms/admin/nav_menu.js +14 -3
  27. data/app/assets/javascripts/camaleon_cms/admin/uploader/_media_manager.js +5 -0
  28. data/app/controllers/camaleon_cms/admin/appearances/nav_menus_controller.rb +8 -6
  29. data/app/controllers/camaleon_cms/admin/appearances/themes_controller.rb +8 -5
  30. data/app/controllers/camaleon_cms/admin/appearances/widgets/assign_controller.rb +7 -2
  31. data/app/controllers/camaleon_cms/admin/appearances/widgets/main_controller.rb +2 -1
  32. data/app/controllers/camaleon_cms/admin/categories_controller.rb +19 -4
  33. data/app/controllers/camaleon_cms/admin/comments_controller.rb +0 -1
  34. data/app/controllers/camaleon_cms/admin/installers_controller.rb +32 -1
  35. data/app/controllers/camaleon_cms/admin/media_controller.rb +66 -14
  36. data/app/controllers/camaleon_cms/admin/plugins_controller.rb +1 -3
  37. data/app/controllers/camaleon_cms/admin/post_tags_controller.rb +10 -4
  38. data/app/controllers/camaleon_cms/admin/posts/drafts_controller.rb +40 -11
  39. data/app/controllers/camaleon_cms/admin/posts_controller.rb +55 -22
  40. data/app/controllers/camaleon_cms/admin/sessions_controller.rb +237 -44
  41. data/app/controllers/camaleon_cms/admin/settings/custom_fields_controller.rb +80 -13
  42. data/app/controllers/camaleon_cms/admin/settings/post_types_controller.rb +5 -2
  43. data/app/controllers/camaleon_cms/admin/settings/sites_controller.rb +26 -3
  44. data/app/controllers/camaleon_cms/admin/settings_controller.rb +5 -3
  45. data/app/controllers/camaleon_cms/admin/user_roles_controller.rb +7 -5
  46. data/app/controllers/camaleon_cms/admin/users_controller.rb +78 -11
  47. data/app/controllers/camaleon_cms/admin_controller.rb +136 -26
  48. data/app/controllers/camaleon_cms/camaleon_controller.rb +37 -92
  49. data/app/controllers/camaleon_cms/frontend_controller.rb +146 -74
  50. data/app/controllers/concerns/camaleon_cms/admin/custom_fields_concern.rb +20 -5
  51. data/app/controllers/concerns/camaleon_cms/frontend_concern.rb +46 -17
  52. data/app/controllers/concerns/camaleon_cms/frontend_visited_state_concern.rb +72 -0
  53. data/app/controllers/concerns/camaleon_cms/hook_lifecycle_concern.rb +104 -0
  54. data/app/controllers/concerns/camaleon_cms/request_context_concern.rb +113 -0
  55. data/app/controllers/concerns/camaleon_cms/runtime_admin_menu_concern.rb +237 -0
  56. data/app/controllers/concerns/camaleon_cms/runtime_captcha_image_concern.rb +13 -0
  57. data/app/controllers/concerns/camaleon_cms/runtime_html_content_concern.rb +143 -0
  58. data/app/controllers/concerns/camaleon_cms/runtime_shortcode_theme_concern.rb +246 -0
  59. data/app/controllers/concerns/camaleon_cms/runtime_state_concern.rb +13 -0
  60. data/app/controllers/concerns/camaleon_cms/runtime_uploader_concern.rb +54 -0
  61. data/app/controllers/concerns/camaleon_cms/session_captcha_runtime_concern.rb +19 -0
  62. data/app/controllers/concerns/camaleon_cms/session_runtime_concern.rb +40 -0
  63. data/app/decorators/camaleon_cms/application_decorator.rb +11 -8
  64. data/app/decorators/camaleon_cms/category_decorator.rb +3 -2
  65. data/app/decorators/camaleon_cms/post_comment_decorator.rb +13 -5
  66. data/app/decorators/camaleon_cms/post_decorator.rb +68 -50
  67. data/app/decorators/camaleon_cms/post_type_decorator.rb +1 -1
  68. data/app/decorators/camaleon_cms/site_decorator.rb +33 -25
  69. data/app/decorators/camaleon_cms/term_taxonomy_decorator.rb +21 -10
  70. data/app/decorators/camaleon_cms/theme_decorator.rb +3 -3
  71. data/app/decorators/camaleon_cms/user_decorator.rb +26 -5
  72. data/app/helpers/camaleon_cms/admin/application_helper.rb +5 -8
  73. data/app/helpers/camaleon_cms/admin/breadcrumb_helper.rb +1 -1
  74. data/app/helpers/camaleon_cms/admin/custom_fields_helper.rb +24 -23
  75. data/app/helpers/camaleon_cms/admin/menus_helper.rb +249 -139
  76. data/app/helpers/camaleon_cms/admin/post_type_helper.rb +34 -17
  77. data/app/helpers/camaleon_cms/camaleon_helper.rb +31 -39
  78. data/app/helpers/camaleon_cms/captcha_helper.rb +73 -53
  79. data/app/helpers/camaleon_cms/comment_helper.rb +19 -7
  80. data/app/helpers/camaleon_cms/content_helper.rb +13 -6
  81. data/app/helpers/camaleon_cms/email_helper.rb +7 -3
  82. data/app/helpers/camaleon_cms/frontend/application_helper.rb +6 -1
  83. data/app/helpers/camaleon_cms/frontend/content_select_helper.rb +34 -20
  84. data/app/helpers/camaleon_cms/frontend/nav_menu_helper.rb +143 -66
  85. data/app/helpers/camaleon_cms/frontend/seo_helper.rb +39 -28
  86. data/app/helpers/camaleon_cms/frontend/site_helper.rb +32 -12
  87. data/app/helpers/camaleon_cms/hooks_helper.rb +14 -4
  88. data/app/helpers/camaleon_cms/html_helper.rb +58 -37
  89. data/app/helpers/camaleon_cms/plugins_helper.rb +23 -24
  90. data/app/helpers/camaleon_cms/session_helper.rb +188 -44
  91. data/app/helpers/camaleon_cms/short_code_helper.rb +181 -85
  92. data/app/helpers/camaleon_cms/site_helper.rb +34 -13
  93. data/app/helpers/camaleon_cms/theme_helper.rb +35 -19
  94. data/app/helpers/camaleon_cms/uploader_helper.rb +19 -473
  95. data/app/helpers/camaleon_cms/user_roles_helper.rb +5 -4
  96. data/app/mailers/camaleon_cms/html_mailer.rb +4 -4
  97. data/app/models/camaleon_cms/ability.rb +15 -7
  98. data/app/models/camaleon_cms/category.rb +6 -6
  99. data/app/models/camaleon_cms/custom_field.rb +15 -6
  100. data/app/models/camaleon_cms/custom_field_group.rb +39 -22
  101. data/app/models/camaleon_cms/custom_fields_relationship.rb +140 -2
  102. data/app/models/camaleon_cms/media.rb +8 -2
  103. data/app/models/camaleon_cms/meta.rb +2 -2
  104. data/app/models/camaleon_cms/nav_menu.rb +5 -3
  105. data/app/models/camaleon_cms/nav_menu_item.rb +16 -8
  106. data/app/models/camaleon_cms/plugin.rb +3 -4
  107. data/app/models/camaleon_cms/post.rb +137 -27
  108. data/app/models/camaleon_cms/post_comment.rb +10 -6
  109. data/app/models/camaleon_cms/post_default.rb +42 -12
  110. data/app/models/camaleon_cms/post_relationship.rb +6 -4
  111. data/app/models/camaleon_cms/post_tag.rb +4 -5
  112. data/app/models/camaleon_cms/post_type.rb +21 -13
  113. data/app/models/camaleon_cms/site.rb +39 -29
  114. data/app/models/camaleon_cms/term_relationship.rb +10 -7
  115. data/app/models/camaleon_cms/term_taxonomy.rb +58 -4
  116. data/app/models/camaleon_cms/theme.rb +2 -4
  117. data/app/models/camaleon_cms/user.rb +17 -5
  118. data/app/models/camaleon_cms/user_role.rb +81 -6
  119. data/app/models/camaleon_cms/widget/assigned.rb +11 -6
  120. data/app/models/camaleon_cms/widget/main.rb +12 -8
  121. data/app/models/camaleon_cms/widget/sidebar.rb +3 -8
  122. data/app/models/camaleon_record.rb +89 -5
  123. data/app/models/concerns/camaleon_cms/categories_tags_for_posts.rb +36 -42
  124. data/app/models/concerns/camaleon_cms/common_relationships.rb +18 -5
  125. data/app/models/concerns/camaleon_cms/content_shortcode_gate.rb +73 -0
  126. data/app/models/concerns/camaleon_cms/custom_fields_read.rb +111 -54
  127. data/app/models/concerns/camaleon_cms/metas.rb +31 -6
  128. data/app/models/concerns/camaleon_cms/normalize_attrs.rb +2 -8
  129. data/app/models/concerns/camaleon_cms/site_default_settings.rb +120 -16
  130. data/app/models/concerns/camaleon_cms/user_methods.rb +44 -19
  131. data/app/models/current_request.rb +8 -1
  132. data/app/uploaders/camaleon_cms_aws_uploader.rb +31 -10
  133. data/app/uploaders/camaleon_cms_local_uploader.rb +76 -19
  134. data/app/uploaders/camaleon_cms_uploader.rb +23 -10
  135. data/app/validators/camaleon_cms/post_uniq_validator.rb +5 -4
  136. data/app/validators/camaleon_cms/uniq_validator.rb +1 -1
  137. data/app/validators/camaleon_cms/user_url_validator.rb +215 -36
  138. data/app/views/camaleon_cms/admin/categories/index.html.erb +2 -2
  139. data/app/views/camaleon_cms/admin/installers/form.html.erb +5 -0
  140. data/app/views/camaleon_cms/admin/installers/welcome.html.erb +30 -6
  141. data/app/views/camaleon_cms/admin/plugins/_plugins_list.html.erb +2 -2
  142. data/app/views/camaleon_cms/admin/post_tags/index.html.erb +2 -2
  143. data/app/views/camaleon_cms/admin/posts/_sidebar.html.erb +1 -1
  144. data/app/views/camaleon_cms/admin/posts/form.html.erb +3 -2
  145. data/app/views/camaleon_cms/admin/posts/index.html.erb +5 -5
  146. data/app/views/camaleon_cms/admin/sessions/back_to_parent.html.erb +39 -0
  147. data/app/views/camaleon_cms/admin/sessions/logout_confirm.html.erb +27 -0
  148. data/app/views/camaleon_cms/admin/settings/_email_settings.html.erb +4 -1
  149. data/app/views/camaleon_cms/admin/settings/custom_fields/_get_items.html.erb +1 -1
  150. data/app/views/camaleon_cms/admin/settings/custom_fields/_render.html.erb +19 -4
  151. data/app/views/camaleon_cms/admin/settings/custom_fields/_render_category_simple.html.erb +1 -1
  152. data/app/views/camaleon_cms/admin/settings/custom_fields/form.html.erb +4 -3
  153. data/app/views/camaleon_cms/admin/settings/shortcodes.html.erb +4 -4
  154. data/app/views/camaleon_cms/admin/settings/site.html.erb +1 -1
  155. data/app/views/camaleon_cms/admin/settings/sites/form.html.erb +1 -1
  156. data/app/views/camaleon_cms/admin/user_roles/form.html.erb +24 -3
  157. data/app/views/camaleon_cms/admin/users/form.html.erb +8 -4
  158. data/app/views/camaleon_cms/admin/users/index.html.erb +1 -1
  159. data/app/views/camaleon_cms/default_theme/partials/_render_custom_field.html.erb +8 -2
  160. data/app/views/camaleon_cms/default_theme/sitemap.html.erb +1 -1
  161. data/app/views/camaleon_cms/default_theme/sitemap.xml.builder +1 -1
  162. data/app/views/layouts/camaleon_cms/admin/_header.html.erb +1 -1
  163. data/config/initializers/action_view.rb +42 -5
  164. data/config/initializers/active_record_extension.rb +13 -27
  165. data/config/initializers/assets.rb +52 -23
  166. data/config/initializers/custom_initializers.rb +1 -1
  167. data/config/locales/camaleon_cms/admin/ar.yml +1 -0
  168. data/config/locales/camaleon_cms/admin/de.yml +1 -0
  169. data/config/locales/camaleon_cms/admin/en.yml +36 -0
  170. data/config/locales/camaleon_cms/admin/es.yml +1 -0
  171. data/config/locales/camaleon_cms/admin/fr.yml +1 -0
  172. data/config/locales/camaleon_cms/admin/it.yml +1 -0
  173. data/config/locales/camaleon_cms/admin/nl.yml +1 -0
  174. data/config/locales/camaleon_cms/admin/pt-BR.yml +1 -0
  175. data/config/locales/camaleon_cms/admin/pt.yml +1 -0
  176. data/config/locales/camaleon_cms/admin/ru.yml +1 -0
  177. data/config/locales/camaleon_cms/admin/uk.yml +1 -0
  178. data/config/locales/camaleon_cms/admin/zh-CH.yml +1 -0
  179. data/config/routes/admin.rb +33 -15
  180. data/config/routes/frontend.rb +21 -15
  181. data/lib/camaleon_cms/assets_precompile.rb +86 -0
  182. data/lib/camaleon_cms/captcha_image_generation.rb +65 -0
  183. data/lib/camaleon_cms/content_security.rb +158 -0
  184. data/lib/camaleon_cms/engine.rb +45 -21
  185. data/lib/camaleon_cms/media_security_headers.rb +27 -0
  186. data/lib/camaleon_cms/setup_token.rb +69 -0
  187. data/lib/camaleon_cms/shortcode_registry.rb +102 -0
  188. data/lib/camaleon_cms/svg_content_checker.rb +123 -0
  189. data/lib/camaleon_cms/task_reporter.rb +14 -0
  190. data/lib/camaleon_cms/unsafe_markup.rb +207 -0
  191. data/lib/camaleon_cms/uploader_content_security.rb +248 -0
  192. data/lib/camaleon_cms/uploader_image_processing.rb +166 -0
  193. data/lib/camaleon_cms/uploader_path_security.rb +146 -0
  194. data/lib/camaleon_cms/uploader_pipeline.rb +350 -0
  195. data/lib/camaleon_cms/uploader_support.rb +86 -0
  196. data/lib/camaleon_cms/version.rb +1 -1
  197. data/lib/camaleon_cms.rb +23 -0
  198. data/lib/ext/hash.rb +28 -2
  199. data/lib/ext/string.rb +10 -5
  200. data/lib/ext/translator.rb +10 -2
  201. data/lib/generators/camaleon_cms/gem_plugin_template/app/controllers/plugins/my_plugin/admin_controller.rb +5 -1
  202. data/lib/generators/camaleon_cms/install_generator.rb +7 -4
  203. data/lib/generators/camaleon_cms/install_template/plugin_routes.rb +5 -12
  204. data/lib/generators/camaleon_cms/theme_generator.rb +5 -10
  205. data/lib/generators/camaleon_cms/theme_template/views/layouts/index.html.erb +3 -1
  206. data/lib/plugin_routes.rb +412 -368
  207. data/lib/tasks/camaleon_cms/camaleon_tasks.rake +2 -1
  208. data/lib/tasks/cross_site_field_groups.rake +74 -0
  209. data/lib/tasks/custom_fields_roles.rake +15 -13
  210. data/lib/tasks/orphaned_comments.rake +42 -0
  211. data/lib/tasks/private_upload_acls.rake +31 -0
  212. data/lib/tasks/site_custom_field_groups.rake +36 -0
  213. data/lib/tasks/unsafe_stored_content.rake +42 -0
  214. data/lib/tasks/unsafe_stored_uploads.rake +70 -0
  215. data/lib/tasks/user_field_groups.rake +27 -0
  216. metadata +125 -4
data/lib/plugin_routes.rb CHANGED
@@ -1,119 +1,33 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  require 'json'
4
- class PluginRoutes
5
- @@_vars = []
6
- @@_after_reload = []
7
- @@anonymous_hooks = {}
8
- # load plugin routes if it is enabled
9
- def self.load(env = 'admin')
10
- plugins = all_enabled_plugins
11
- res = ''
12
- case env
13
- when 'front'
14
- res << "namespace :plugins do \n"
15
- plugins.each do |plugin|
16
- res << "namespace '#{plugin['key']}' do \n"
17
- begin
18
- res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
19
- rescue StandardError
20
- ''
21
- end
22
- res << "end\n"
23
- end
24
- res << "end\n"
25
-
26
- when 'admin' # admin
27
- res << "scope 'admin', as: 'admin' do \n"
28
- res << "namespace :plugins do \n"
29
- plugins.each do |plugin|
30
- res << "namespace '#{plugin['key']}' do \n"
31
- begin
32
- res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
33
- rescue StandardError
34
- ''
35
- end
36
- res << "end\n"
37
- end
38
- res << "end\n"
39
- res << "end\n"
40
- else # main
41
- plugins.each do |plugin|
42
- res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
43
- rescue StandardError
44
- ''
45
- end
46
- end
47
- res + load_themes(env)
48
- end
49
-
50
- def self.load_themes(env = 'admin')
51
- plugins = all_enabled_themes
52
- res = ''
53
- case env
54
- when 'front'
55
- res << "namespace :themes do \n"
56
- plugins.each do |plugin|
57
- res << "namespace '#{plugin['key']}' do \n"
58
- begin
59
- res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
60
- rescue StandardError
61
- ''
62
- end
63
- res << "end\n"
64
- end
65
- res << "end\n"
66
-
67
- when 'admin' # admin
68
- res << "scope 'admin', as: 'admin' do \n"
69
- res << "namespace :themes do \n"
70
- plugins.each do |plugin|
71
- res << "namespace '#{plugin['key']}' do \n"
72
- begin
73
- res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
74
- rescue StandardError
75
- ''
76
- end
77
- res << "end\n"
78
- end
79
- res << "end\n"
80
- res << "end\n"
81
- else # main
82
- plugins.each do |plugin|
83
- res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
84
- rescue StandardError
85
- ''
86
- end
87
- end
88
- res
89
- end
4
+ require 'monitor'
90
5
 
6
+ class PluginRoutes
91
7
  class << self
92
8
  # return plugin information
93
9
  def plugin_info(plugin_key)
94
- all_plugins.each { |p| return p if p['key'] == plugin_key || p['path'].split('/').last == plugin_key }
95
- nil
10
+ all_plugins.find { |p| p['key'] == plugin_key || p['path'].split('/').last == plugin_key }
96
11
  end
97
12
 
98
13
  # return theme information
99
14
  # if theme_name is nil, the use current site theme
100
15
  def theme_info(theme_name)
101
- all_themes.each { |p| return p if p['key'] == theme_name }
102
- nil
16
+ all_themes.find { |p| p['key'] == theme_name }
103
17
  end
104
18
 
105
19
  # return system static settings (config.json values)
106
20
  def static_system_info
107
21
  r = cache_variable('statis_system_info')
108
- return r unless r.nil?
22
+ return r if r
109
23
 
110
24
  settings = {}
111
25
 
112
26
  gem_settings = File.join($camaleon_engine_dir, 'config', 'system.json')
113
- app_settings = Rails.root.join('config', 'system.json')
27
+ app_settings = Rails.root.join('config/system.json')
114
28
 
115
- settings = settings.merge(JSON.parse(File.read(gem_settings))) if File.exist?(gem_settings)
116
- settings = settings.merge(JSON.parse(File.read(app_settings))) if File.exist?(app_settings)
29
+ settings.merge!(JSON.parse(File.read(gem_settings))) if File.exist?(gem_settings)
30
+ settings.merge!(JSON.parse(File.read(app_settings))) if File.exist?(app_settings)
117
31
 
118
32
  # custom settings
119
33
  settings['key'] = 'system'
@@ -126,15 +40,13 @@ class PluginRoutes
126
40
 
127
41
  # convert action parameter into hash
128
42
  def fixActionParameter(h)
129
- (if h.is_a?(ActionController::Parameters)
130
- begin
131
- h.permit!.to_h
132
- rescue StandardError
133
- h.to_hash
134
- end
135
- else
136
- h
137
- end)
43
+ return h unless h.is_a?(ActionController::Parameters)
44
+
45
+ begin
46
+ h.permit!.to_h
47
+ rescue StandardError
48
+ h.to_hash
49
+ end
138
50
  end
139
51
 
140
52
  # add a new anonymous hook
@@ -144,15 +56,14 @@ class PluginRoutes
144
56
  # @param callback [Lambda], anonymous function to be called when the hook was called
145
57
  # @return nil
146
58
  def add_anonymous_hook(hook_key, callback, hook_id = '')
147
- @@anonymous_hooks[hook_key] ||= []
148
- @@anonymous_hooks[hook_key] << { id: hook_id, callback: callback }
59
+ (anonymous_hooks[hook_key] ||= []) << { id: hook_id, callback: callback }
149
60
  end
150
61
 
151
62
  # return all registered anonymous hooks for hook_key
152
63
  # @param hook_key [String] name of the hook
153
64
  # @return [Array] array of hooks for hook_key
154
65
  def get_anonymous_hooks(hook_key)
155
- (@@anonymous_hooks[hook_key.to_s] || []).map { |item| item[:callback] }
66
+ (anonymous_hooks[hook_key.to_s] || []).map { |item| item[:callback] }
156
67
  end
157
68
 
158
69
  # return all registered anonymous hooks for hook_key
@@ -160,323 +71,456 @@ class PluginRoutes
160
71
  # @param hook_id [String] identifier of the anonymous hooks
161
72
  # @return [Array] array of hooks for hook_key
162
73
  def remove_anonymous_hook(hook_key, hook_id)
163
- (@@anonymous_hooks[hook_key.to_s] || []).delete_if { |item| item[:id] == hook_id }
74
+ (anonymous_hooks[hook_key.to_s] || []).delete_if { |item| item[:id] == hook_id }
164
75
  end
165
76
 
166
77
  # return the class name for user model
167
78
  def get_user_class_name
168
79
  static_system_info['user_model'].presence || 'CamaleonCms::User'
169
80
  end
170
- end
171
81
 
172
- # reload routes
173
- def self.reload
174
- @@all_sites = nil
175
- @@_vars.each { |v| class_variable_set("@@cache_#{v}", nil) }
176
- Rails.application.reload_routes!
177
- @@_after_reload.uniq.each(&:call)
178
- end
82
+ # load plugin routes if it is enabled
83
+ def load(env = 'admin')
84
+ plugins = all_enabled_plugins
85
+ res = ''
86
+ case env
87
+ when 'front'
88
+ res << "namespace :plugins do \n"
89
+ plugins.each do |plugin|
90
+ res << "namespace '#{plugin['key']}' do \n"
91
+ begin
92
+ res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
93
+ rescue StandardError
94
+ ''
95
+ end
96
+ res << "end\n"
97
+ end
98
+ res << "end\n"
179
99
 
180
- # Add a callable (Proc/Lambda) to run after routes reload; strings are not supported.
181
- def self.add_after_reload_routes(command)
182
- @@_after_reload << (command.is_a?(String) ? raise(ArgumentError, 'Expected a callable (Proc/Lambda), not a String') : command)
183
- end
100
+ when 'admin' # admin
101
+ res << "scope 'admin', as: 'admin' do \n"
102
+ res << "namespace :plugins do \n"
103
+ plugins.each do |plugin|
104
+ res << "namespace '#{plugin['key']}' do \n"
105
+ begin
106
+ res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
107
+ rescue StandardError
108
+ ''
109
+ end
110
+ res << "end\n"
111
+ end
112
+ res << "end\n"
113
+ res << "end\n"
114
+ else # main
115
+ plugins.each do |plugin|
116
+ res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
117
+ rescue StandardError
118
+ ''
119
+ end
120
+ end
121
+ res + load_themes(env)
122
+ end
184
123
 
185
- # return all enabled plugins []
186
- def self.enabled_plugins(site)
187
- r = cache_variable("enable_plugins_site_#{site.id}")
188
- return r unless r.nil?
124
+ def load_themes(env = 'admin')
125
+ plugins = all_enabled_themes
126
+ res = ''
127
+ case env
128
+ when 'front'
129
+ res << "namespace :themes do \n"
130
+ plugins.each do |plugin|
131
+ res << "namespace '#{plugin['key']}' do \n"
132
+ begin
133
+ res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
134
+ rescue StandardError
135
+ ''
136
+ end
137
+ res << "end\n"
138
+ end
139
+ res << "end\n"
189
140
 
190
- res = []
191
- enabled_ps = site.plugins.active.pluck(:slug)
192
- all_plugins.each do |plugin|
193
- res << plugin if enabled_ps.include?(plugin['key'])
141
+ when 'admin' # admin
142
+ res << "scope 'admin', as: 'admin' do \n"
143
+ res << "namespace :themes do \n"
144
+ plugins.each do |plugin|
145
+ res << "namespace '#{plugin['key']}' do \n"
146
+ begin
147
+ res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
148
+ rescue StandardError
149
+ ''
150
+ end
151
+ res << "end\n"
152
+ end
153
+ res << "end\n"
154
+ res << "end\n"
155
+ else # main
156
+ plugins.each do |plugin|
157
+ res << "#{File.open(File.join(plugin['path'], 'config', "routes_#{env}.txt")).read}\n"
158
+ rescue StandardError
159
+ ''
160
+ end
161
+ end
162
+ res
194
163
  end
195
- res = res.sort_by { |e| e['position'] || 10 }
196
- cache_variable("enable_plugins_site_#{site.id}", res)
197
- end
198
164
 
199
- # return all enabled apps for site (themes + system + plugins) []
200
- # theme_slug: current theme slug
201
- def self.enabled_apps(site, theme_slug = nil)
202
- theme_slug ||= site.get_theme_slug
203
- r = cache_variable("enabled_apps_#{site.id}_#{theme_slug}")
204
- return r unless r.nil?
165
+ # reload routes (thread-safe)
166
+ def reload
167
+ reload_monitor.synchronize do
168
+ @all_sites = nil
169
+ cache.clear
170
+ Rails.application.reload_routes!
171
+ after_reload_callbacks.uniq.each(&:call)
172
+ end
173
+ end
205
174
 
206
- res = [system_info] + enabled_plugins(site) + [theme_info(theme_slug)]
207
- cache_variable("enabled_apps_#{site.id}_#{theme_slug}", res)
208
- end
175
+ # Draw the route table at boot so the first request is never served against a half-built set
176
+ # of routes. Production already eager-loads routes; this closes the development window where
177
+ # the first request after a restart races the (multi-site) draw. Guarded by db_installed? and
178
+ # rescued so boot never aborts when the DB is unavailable (migrations, asset precompile, or a
179
+ # fresh install before db:create).
180
+ def draw_routes_eagerly
181
+ return if Rails.application.config.eager_load # production draws routes at boot already
182
+ # Skip while a db: Rake task runs (db:migrate, db:schema:load, app:db:test:prepare, ...): it
183
+ # boots against a schema that is mid-change, so drawing here would query that schema -- and it
184
+ # never serves a request that could race the draw. Other non-server processes (console,
185
+ # workers) still draw: Rails exposes no reliable, version-stable "is this the web server?"
186
+ # signal, and the draw is otherwise bounded and safe (a single guarded, rescued, idempotent
187
+ # draw over long-stable columns), so scoping it further is not worth a fragile gate.
188
+ return if running_db_rake_task?
189
+ return unless db_installed?
190
+
191
+ Rails.application.reload_routes!
192
+ rescue ActiveRecord::ActiveRecordError => e
193
+ # Only swallow database-unavailability (migrations, asset precompile, a fresh install before
194
+ # db:create) so boot never aborts on it. A route-file syntax error, a raised constraint lambda
195
+ # or any other bug in the draw is NOT a boot-safety concern and must surface, not be logged and
196
+ # hidden here where nothing would ever redraw and reveal it.
197
+ Rails.logger&.warn("Camaleon CMS: skipped eager route draw at boot (#{e.class}: #{e.message})")
198
+ nil
199
+ end
209
200
 
210
- # return all enabled apps as []: system, themes, plugins
211
- def self.all_enabled_apps
212
- [system_info] + all_enabled_themes + all_enabled_plugins
213
- end
201
+ # Add a callable (Proc/Lambda) to run after routes reload; strings are not supported.
202
+ def add_after_reload_routes(command)
203
+ raise(ArgumentError, 'Expected a callable (Proc/Lambda), not a String') if command.is_a?(String)
214
204
 
215
- # return all enabled themes (a theme is enabled if at least one site is assigned)
216
- def self.all_enabled_themes
217
- r = cache_variable('all_enabled_themes')
218
- return r unless r.nil?
205
+ after_reload_callbacks << command
206
+ end
219
207
 
220
- res = []
221
- get_sites.each do |site|
222
- i = theme_info(site.get_theme_slug)
223
- res << i if i.present?
208
+ # return all enabled plugins []
209
+ def enabled_plugins(site)
210
+ r = cache_variable("enable_plugins_site_#{site.id}")
211
+ return r if r
212
+
213
+ enabled_ps = site.plugins.active.pluck(:slug)
214
+ res = all_plugins.each_with_object([]) do |plugin, ary|
215
+ ary << plugin if enabled_ps.include?(plugin['key'])
216
+ end
217
+ res = res.sort_by { |e| e['position'] || 10 }
218
+ cache_variable("enable_plugins_site_#{site.id}", res)
224
219
  end
225
- cache_variable('all_enabled_themes', res)
226
- end
227
220
 
228
- # return all enabled plugins (a theme is enabled if at least one site has installed)
229
- def self.all_enabled_plugins
230
- r = cache_variable('all_enabled_plugins')
231
- return r unless r.nil?
221
+ # return all enabled apps for site (themes + system + plugins) []
222
+ # theme_slug: current theme slug
223
+ def enabled_apps(site, theme_slug = nil)
224
+ theme_slug ||= site.get_theme_slug
225
+ r = cache_variable("enabled_apps_#{site.id}_#{theme_slug}")
226
+ return r if r
232
227
 
233
- res = []
234
- enabled_ps = []
235
- get_sites.each { |site| enabled_ps += site.plugins.active.pluck(:slug) }
236
- all_plugins.each do |plugin|
237
- res << plugin if enabled_ps.include?(plugin['key'])
228
+ res = [system_info] + enabled_plugins(site) + [theme_info(theme_slug)]
229
+ cache_variable("enabled_apps_#{site.id}_#{theme_slug}", res)
230
+ end
231
+
232
+ # return all enabled apps as []: system, themes, plugins
233
+ def all_enabled_apps
234
+ [system_info] + all_enabled_themes + all_enabled_plugins
238
235
  end
239
- cache_variable('all_enabled_plugins', res)
240
- end
241
236
 
242
- # all helpers of enabled plugins for site
243
- def self.site_plugin_helpers(site)
244
- r = cache_variable('site_plugin_helpers')
245
- return r unless r.nil?
237
+ # return all enabled themes (a theme is enabled if at least one site is assigned)
238
+ def all_enabled_themes
239
+ r = cache_variable('all_enabled_themes')
240
+ # Do not treat an empty result as a cache hit (an empty [] is truthy): if a draw runs before
241
+ # the DB is ready, get_sites returns [] and this would otherwise cache [] permanently, matching
242
+ # the self-healing all_plugins/all_themes below rather than the sticky-empty behavior.
243
+ return r if r.present?
244
+
245
+ res = get_sites.each_with_object([]) do |site, ary|
246
+ i = theme_info(site.get_theme_slug)
247
+ ary << i if i.present?
248
+ end
249
+ cache_variable('all_enabled_themes', res)
250
+ end
246
251
 
247
- res = []
248
- enabled_apps(site).each do |settings|
249
- res += settings['helpers'] if settings['helpers'].present?
252
+ # return all enabled plugins (a theme is enabled if at least one site has installed)
253
+ def all_enabled_plugins
254
+ r = cache_variable('all_enabled_plugins')
255
+ return r if r.present? # an empty [] must not stick as a cache hit -- see all_enabled_themes
256
+
257
+ # Empty get_sites (the DB is not ready during early boot, or there simply are no sites) means
258
+ # no DB work: gate the batched query on it here, as one explicit early return, so the query
259
+ # never runs against a table that may not exist yet and aborts route loading. get_sites rescues
260
+ # to [] on any DB error, so this single guard keeps the whole draw path safe -- and any batched
261
+ # query added below inherits it, rather than each repeating a per-call emptiness check.
262
+ return [] if get_sites.empty?
263
+
264
+ # One query for every enabled plugin slug across all sites, rather than a
265
+ # `site.plugins.active.pluck` per site (the N+1 that dominated multi-site route drawing). A
266
+ # subquery over the site ids avoids marshaling every id into an IN(...) bind list, which can
267
+ # exceed SQLite's SQLITE_MAX_VARIABLE_NUMBER on very large multi-site installs; Postgres and
268
+ # MySQL handle either form.
269
+ enabled_ps = CamaleonCms::Plugin.active.where(parent_id: CamaleonCms::Site.select(:id)).distinct.pluck(:slug)
270
+ res = all_plugins.each_with_object([]) do |plugin, ary|
271
+ ary << plugin if enabled_ps.include?(plugin['key'])
272
+ end
273
+ cache_variable('all_enabled_plugins', res)
250
274
  end
251
- cache_variable('site_plugin_helpers', res)
252
- end
253
275
 
254
- # all helpers of enabled plugins
255
- def self.all_helpers
256
- r = cache_variable('plugins_helper')
257
- return r unless r.nil?
276
+ # all helpers of enabled plugins for site
277
+ def site_plugin_helpers(site)
278
+ r = cache_variable('site_plugin_helpers')
279
+ return r if r
258
280
 
259
- res = []
260
- all_apps.each do |settings|
261
- res += settings['helpers'] if settings['helpers'].present?
281
+ res = enabled_apps(site).filter_map { |settings| settings['helpers'].presence }.flatten
282
+ cache_variable('site_plugin_helpers', res)
262
283
  end
263
- cache_variable('plugins_helper', res.uniq)
264
- end
265
284
 
266
- # destroy plugin
267
- def self.destroy_plugin(plugin_key)
268
- begin
269
- FileUtils.rm_r(Rails.root.join('app', 'apps', 'plugins', plugin_key))
270
- rescue StandardError
271
- ''
285
+ # all helpers of enabled plugins
286
+ def all_helpers
287
+ r = cache_variable('plugins_helper')
288
+ return r if r
289
+
290
+ res = all_apps.filter_map { |settings| settings['helpers'].presence }.flatten
291
+ cache_variable('plugins_helper', res.uniq)
272
292
  end
273
- PluginRoutes.reload
274
- end
275
293
 
276
- def self.cache_variable(var_name, value = nil)
277
- @@_vars.push(var_name).uniq!
278
- # if Rails.env != "development" # disable cache plugin routes for development mode
279
- cache = begin
280
- class_variable_get("@@cache_#{var_name}")
294
+ # destroy plugin
295
+ def destroy_plugin(plugin_key)
296
+ begin
297
+ FileUtils.rm_r(Rails.root.join('app', 'apps', 'plugins', plugin_key))
298
+ rescue StandardError
299
+ nil
300
+ end
301
+ PluginRoutes.reload
302
+ end
303
+
304
+ def cache_variable(var_name, value = nil)
305
+ reload_monitor.synchronize do
306
+ if value.nil?
307
+ cache[var_name]
308
+ else
309
+ cache[var_name] = value
310
+ end
311
+ end
312
+ end
313
+
314
+ # return all sites registered for Plugin routes
315
+ def get_sites
316
+ # Eager-load metas and post_types so the per-site reads route drawing performs come from the
317
+ # loaded associations instead of one query per site: metas back the option/language/theme
318
+ # lookups (get_meta checks metas.loaded?), and post_types back the frontend post-type route
319
+ # loop. On large multi-site installs those N+1s are the bulk of cold-boot route-draw time --
320
+ # the window where the first request races a half-built table.
321
+ #
322
+ # The whole metas set is loaded on purpose, not a scoped subset: get_meta's loaded branch reads
323
+ # a key absent from the loaded records as unset, so preloading only _default/languages_site
324
+ # would make every other site meta read silently return its default. Site-level metas are few
325
+ # rows per site, so this bounded over-fetch is the safe trade against that correctness hazard.
326
+ @all_sites ||= CamaleonCms::Site.includes(:metas, :post_types).order(id: :asc).to_a
281
327
  rescue StandardError
282
- nil
328
+ []
283
329
  end
284
- return cache if value.nil?
285
330
 
286
- # end
287
- class_variable_set("@@cache_#{var_name}", value)
288
- value
289
- end
331
+ # check if db migrate already done
332
+ def db_installed?
333
+ @db_installed ||= ActiveRecord::Base.connection.table_exists?(CamaleonCms::Site.table_name)
334
+ end
290
335
 
291
- # return all sites registered for Plugin routes
292
- def self.get_sites
293
- @@all_sites ||= CamaleonCms::Site.order(id: :asc).all.to_a
294
- rescue StandardError
295
- []
296
- end
336
+ # return all locales for all sites joined by |
337
+ def all_locales
338
+ r = cache_variable('site_all_locales')
339
+ # A blank '' must not stick as a hit: an empty all_locales makes the frontend
340
+ # `locale: /#{all_locales}/` constraint an empty regex `//` that matches anything.
341
+ return r if r.present?
297
342
 
298
- # check if db migrate already done
299
- def self.db_installed?
300
- @@is_db_installed ||= ActiveRecord::Base.connection.table_exists?(CamaleonCms::Site.table_name)
301
- end
343
+ res = get_sites.flat_map(&:get_languages)
344
+ cache_variable('site_all_locales', res.uniq.join('|'))
345
+ end
302
346
 
303
- # return all locales for all sites joined by |
304
- def self.all_locales
305
- r = cache_variable('site_all_locales')
306
- return r unless r.nil?
347
+ # return all translations for all languages, sample: ['Sample', 'Ejemplo', '....']
348
+ def all_translations(key, *args)
349
+ args = args.extract_options!
350
+ all_locales.split('|').map { |_l| I18n.t(key, **args.merge({ locale: _l })) }.uniq
351
+ end
307
352
 
308
- res = []
309
- get_sites.each do |s|
310
- res += s.get_languages
353
+ # return app's directory path
354
+ def apps_dir
355
+ @apps_dir ||= Rails.root.join('app/apps').to_s
311
356
  end
312
- cache_variable('site_all_locales', res.uniq.join('|'))
313
- end
314
357
 
315
- # return all translations for all languages, sample: ['Sample', 'Ejemplo', '....']
316
- def self.all_translations(key, *args)
317
- args = args.extract_options!
318
- all_locales.split('|').map { |_l| I18n.t(key, **args.merge({ locale: _l })) }.uniq
319
- end
358
+ # return all plugins located in cms and in this project
359
+ def all_plugins
360
+ camaleon_gem = get_gem('camaleon_cms')
361
+ return [] unless camaleon_gem
362
+
363
+ r = cache_variable('all_plugins')
364
+ return r if r.present?
365
+
366
+ res = get_gem_plugins
367
+ entries = %w[. ..]
368
+ res.each { |plugin| entries << plugin['key'] }
369
+ (Dir["#{apps_dir}/plugins/*"] + Dir["#{camaleon_gem.gem_dir}/app/apps/plugins/*"]).each do |path|
370
+ entry = path.split('/').last
371
+ config = File.join(path, 'config', 'config.json')
372
+ next if entries.include?(entry) || !File.directory?(path) || !File.exist?(config)
373
+
374
+ p = JSON.parse(File.read(config))
375
+ p = begin
376
+ p.with_indifferent_access
377
+ rescue StandardError
378
+ p
379
+ end
380
+ p['key'] = entry
381
+ p['path'] = path
382
+ p['kind'] = 'plugin'
383
+ res << p
384
+ entries << entry
385
+ end
386
+ cache_variable('all_plugins', res)
387
+ end
320
388
 
321
- # return all locales for translated routes
322
- def self.all_locales_for_routes
323
- r = cache_variable('all_locales_for_routes')
324
- return r unless r.nil?
389
+ # return an array of all themes installed for all sites
390
+ def all_themes
391
+ camaleon_gem = get_gem('camaleon_cms')
392
+ return [] unless camaleon_gem
393
+
394
+ r = cache_variable('all_themes')
395
+ return r if r.present?
396
+
397
+ res = get_gem_themes
398
+ entries = %w[. ..]
399
+ res.each { |theme| entries << theme['key'] }
400
+ Dir["#{apps_dir}/themes/*"].each do |path|
401
+ entry = path.split('/').last
402
+ config = File.join(path, 'config', 'config.json')
403
+ next if entries.include?(entry) || !File.directory?(path) || !File.exist?(config)
404
+
405
+ p = JSON.parse(File.read(config))
406
+ p = begin
407
+ p.with_indifferent_access
408
+ rescue StandardError
409
+ p
410
+ end
411
+ p['key'] = entry
412
+ p['path'] = path
413
+ p['kind'] = 'theme'
414
+ p['title'] = p['name']
415
+ res << p
416
+ entries << entry
417
+ end
418
+ cache_variable('all_themes', res)
419
+ end
325
420
 
326
- res = {}
327
- all_locales.split('|').each do |l|
328
- res[l] = "_#{l}"
421
+ # return all apps loaded
422
+ def all_apps
423
+ all_plugins + all_themes
329
424
  end
330
- res[false] = ''
331
- cache_variable('all_locales_for_routes', res)
332
- end
333
425
 
334
- # return apps directory path
335
- def self.apps_dir
336
- Rails.root.join('app', 'apps').to_s
337
- end
426
+ # return all plugins registered as gems
427
+ def get_gem_plugins
428
+ Gem::Specification.each_with_object([]) do |gem, ary|
429
+ path = gem.gem_dir
430
+ config = File.join(path, 'config', 'camaleon_plugin.json')
431
+ next unless File.exist?(config)
338
432
 
339
- # return all plugins located in cms and in this project
340
- def self.all_plugins
341
- camaleon_gem = get_gem('camaleon_cms')
342
- return [] unless camaleon_gem
343
-
344
- r = cache_variable('all_plugins')
345
- return r unless r.nil? || r == []
346
-
347
- res = get_gem_plugins
348
- entries = ['.', '..']
349
- res.each { |plugin| entries << plugin['key'] }
350
- (Dir["#{apps_dir}/plugins/*"] + Dir["#{camaleon_gem.gem_dir}/app/apps/plugins/*"]).each do |path|
351
- entry = path.split('/').last
352
- config = File.join(path, 'config', 'config.json')
353
- next if entries.include?(entry) || !File.directory?(path) || !File.exist?(config)
354
-
355
- p = JSON.parse(File.read(config))
356
- p = begin
357
- p.with_indifferent_access
358
- rescue StandardError
359
- p
433
+ p = JSON.parse(File.read(config))
434
+ p = begin
435
+ p.with_indifferent_access
436
+ rescue StandardError
437
+ p
438
+ end
439
+ p['key'] = gem.name if p['key'].nil? # TODO: REVIEW ERROR FOR conflict plugin keys
440
+ p['version'] = gem.version.to_s
441
+ p['path'] = path
442
+ p['kind'] = 'plugin'
443
+ p['descr'] = gem.description if p['descr'].blank?
444
+ p['gem_mode'] = true
445
+ ary << p
360
446
  end
361
- p['key'] = entry
362
- p['path'] = path
363
- p['kind'] = 'plugin'
364
- res << p
365
- entries << entry
366
447
  end
367
- cache_variable('all_plugins', res)
368
- end
369
448
 
370
- # return an array of all themes installed for all sites
371
- def self.all_themes
372
- camaleon_gem = get_gem('camaleon_cms')
373
- return [] unless camaleon_gem
374
-
375
- r = cache_variable('all_themes')
376
- return r unless r.nil? || r == []
377
-
378
- res = get_gem_themes
379
- entries = %w[. ..]
380
- res.each { |theme| entries << theme['key'] }
381
- Dir["#{apps_dir}/themes/*"].each do |path|
382
- entry = path.split('/').last
383
- config = File.join(path, 'config', 'config.json')
384
- next if entries.include?(entry) || !File.directory?(path) || !File.exist?(config)
385
-
386
- p = JSON.parse(File.read(config))
387
- p = begin
388
- p.with_indifferent_access
389
- rescue StandardError
390
- p
449
+ # return all themes registered as gems
450
+ def get_gem_themes
451
+ Gem::Specification.each_with_object([]) do |gem, ary|
452
+ path = gem.gem_dir
453
+ config = File.join(path, 'config', 'camaleon_theme.json')
454
+ next unless File.exist?(config)
455
+
456
+ p = JSON.parse(File.read(config))
457
+ p = begin
458
+ p.with_indifferent_access
459
+ rescue StandardError
460
+ p
461
+ end
462
+ p['key'] = gem.name if p['key'].nil? # TODO: REVIEW ERROR FOR conflict plugin keys
463
+ p['path'] = path
464
+ p['kind'] = 'theme'
465
+ p['gem_mode'] = true
466
+ ary << p
391
467
  end
392
- p['key'] = entry
393
- p['path'] = path
394
- p['kind'] = 'theme'
395
- p['title'] = p['name']
396
- res << p
397
- entries << entry
398
- end
399
- cache_variable('all_themes', res)
400
- end
468
+ end
401
469
 
402
- # return all apps loaded
403
- def self.all_apps
404
- all_plugins + all_themes
405
- end
470
+ # check if a gem is available or not
471
+ # Arguemnts:
472
+ # name: name of the gem
473
+ # return (Boolean) true/false
474
+ def get_gem(name)
475
+ Gem::Specification.find_by_name(name)
476
+ rescue Gem::LoadError
477
+ false
478
+ rescue StandardError
479
+ Gem.available?(name)
480
+ end
406
481
 
407
- # return all plugins registered as gems
408
- def self.get_gem_plugins
409
- entries = []
410
- Gem::Specification.each do |gem|
411
- path = gem.gem_dir
412
- config = File.join(path, 'config', 'camaleon_plugin.json')
413
- next unless File.exist?(config)
414
-
415
- p = JSON.parse(File.read(config))
416
- p = begin
417
- p.with_indifferent_access
482
+ # return the default url options for Camaleon CMS
483
+ def default_url_options
484
+ options = { host: begin
485
+ CamaleonCms::Site.main_site.slug
418
486
  rescue StandardError
419
- p
420
- end
421
- p['key'] = gem.name if p['key'].nil? # TODO: REVIEW ERROR FOR conflict plugin keys
422
- p['version'] = gem.version.to_s
423
- p['path'] = path
424
- p['kind'] = 'plugin'
425
- p['descr'] = gem.description unless p['descr'].present?
426
- p['gem_mode'] = true
427
- entries << p
428
- end
429
- entries
430
- end
487
+ ''
488
+ end }
489
+ options[:protocol] = 'https' if Rails.application.config.force_ssl
490
+ options
491
+ end
431
492
 
432
- # return all themes registered as gems
433
- def self.get_gem_themes
434
- entries = []
435
- Gem::Specification.each do |gem|
436
- path = gem.gem_dir
437
- config = File.join(path, 'config', 'camaleon_theme.json')
438
- next unless File.exist?(config)
439
-
440
- p = JSON.parse(File.read(config))
441
- p = begin
442
- p.with_indifferent_access
443
- rescue StandardError
444
- p
445
- end
446
- p['key'] = gem.name if p['key'].nil? # TODO: REVIEW ERROR FOR conflict plugin keys
447
- p['path'] = path
448
- p['kind'] = 'theme'
449
- p['gem_mode'] = true
450
- entries << p
493
+ def migration_class
494
+ ActiveRecord::Migration[4.2]
451
495
  end
452
- entries
453
- end
454
496
 
455
- # check if a gem is available or not
456
- # Arguemnts:
457
- # name: name of the gem
458
- # return (Boolean) true/false
459
- def self.get_gem(name)
460
- Gem::Specification.find_by_name(name)
461
- rescue Gem::LoadError
462
- false
463
- rescue StandardError
464
- Gem.available?(name)
465
- end
497
+ private
466
498
 
467
- # return the default url options for Camaleon CMS
468
- def self.default_url_options
469
- options = { host: begin
470
- CamaleonCms::Site.main_site.slug
471
- rescue StandardError
472
- ''
473
- end }
474
- options.merge!({ protocol: 'https' }) if Rails.application.config.force_ssl
475
- options
476
- end
499
+ # True when this process is running a task in the `db:` Rake namespace (db:migrate,
500
+ # db:schema:load, ... or their engine-prefixed forms like app:db:test:prepare), whether launched
501
+ # through `rails` or `rake`. Rake.application is absent outside a Rake run (the web server,
502
+ # `rails console`, `rails runner`), so this is false there.
503
+ def running_db_rake_task?
504
+ return false unless defined?(Rake) && Rake.respond_to?(:application)
477
505
 
478
- def self.migration_class
479
- ActiveRecord::Migration[4.2]
506
+ Rake.application.top_level_tasks.any? { |task| task.to_s.split(':').include?('db') }
507
+ end
508
+
509
+ def anonymous_hooks
510
+ @anonymous_hooks ||= {}
511
+ end
512
+
513
+ def after_reload_callbacks
514
+ @after_reload_callbacks ||= []
515
+ end
516
+
517
+ def reload_monitor
518
+ @reload_monitor ||= Monitor.new
519
+ end
520
+
521
+ def cache
522
+ @cache ||= {}
523
+ end
480
524
  end
481
525
  end
482
526
  CamaManager = PluginRoutes