alchemy_cms 2.6.3 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +14 -0
  3. data/.travis.yml +1 -1
  4. data/Gemfile +7 -6
  5. data/README.md +15 -5
  6. data/alchemy_cms.gemspec +3 -2
  7. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +9 -17
  8. data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +70 -0
  9. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +80 -0
  10. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +43 -19
  11. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +3 -1
  12. data/app/assets/javascripts/alchemy/alchemy.js +4 -2
  13. data/app/assets/javascripts/alchemy/alchemy.onload.js.coffee +1 -1
  14. data/app/assets/javascripts/alchemy/alchemy.spinner.js.coffee +14 -0
  15. data/app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee.erb +96 -0
  16. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +22 -0
  17. data/app/assets/javascripts/alchemy/alchemy.windows.js.coffee +28 -17
  18. data/app/assets/stylesheets/alchemy/base.scss +6 -0
  19. data/app/assets/stylesheets/alchemy/elements.scss +2 -28
  20. data/app/assets/stylesheets/alchemy/errors.scss +1 -1
  21. data/app/assets/stylesheets/alchemy/menubar.css.scss +2 -0
  22. data/app/assets/stylesheets/alchemy/sitemap.scss +21 -34
  23. data/app/assets/stylesheets/alchemy/tables.scss +13 -3
  24. data/app/controllers/alchemy/admin/attachments_controller.rb +10 -5
  25. data/app/controllers/alchemy/admin/base_controller.rb +19 -0
  26. data/app/controllers/alchemy/admin/contents_controller.rb +1 -4
  27. data/app/controllers/alchemy/admin/dashboard_controller.rb +2 -1
  28. data/app/controllers/alchemy/admin/elements_controller.rb +1 -1
  29. data/app/controllers/alchemy/admin/essence_files_controller.rb +1 -1
  30. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +70 -56
  31. data/app/controllers/alchemy/admin/pages_controller.rb +37 -114
  32. data/app/controllers/alchemy/admin/pictures_controller.rb +5 -12
  33. data/app/controllers/alchemy/admin/resources_controller.rb +3 -1
  34. data/app/controllers/alchemy/admin/trash_controller.rb +1 -1
  35. data/app/controllers/alchemy/attachments_controller.rb +1 -1
  36. data/app/controllers/alchemy/base_controller.rb +3 -15
  37. data/app/controllers/alchemy/messages_controller.rb +4 -10
  38. data/app/controllers/alchemy/pages_controller.rb +6 -6
  39. data/app/controllers/alchemy/passwords_controller.rb +1 -1
  40. data/app/controllers/alchemy/user_sessions_controller.rb +1 -1
  41. data/app/helpers/alchemy/admin/base_helper.rb +49 -230
  42. data/app/helpers/alchemy/admin/contents_helper.rb +5 -1
  43. data/app/helpers/alchemy/admin/elements_helper.rb +19 -47
  44. data/app/helpers/alchemy/admin/essences_helper.rb +59 -17
  45. data/app/helpers/alchemy/admin/navigation_helper.rb +204 -0
  46. data/app/helpers/alchemy/admin/pages_helper.rb +22 -79
  47. data/app/helpers/alchemy/admin/pictures_helper.rb +1 -1
  48. data/app/helpers/alchemy/admin/tags_helper.rb +42 -0
  49. data/app/helpers/alchemy/base_helper.rb +0 -11
  50. data/app/helpers/alchemy/elements_helper.rb +48 -25
  51. data/app/helpers/alchemy/essences_helper.rb +0 -20
  52. data/app/helpers/alchemy/pages_helper.rb +18 -14
  53. data/app/helpers/alchemy/url_helper.rb +1 -0
  54. data/app/mailers/alchemy/messages.rb +4 -6
  55. data/app/models/alchemy/attachment.rb +3 -0
  56. data/app/models/alchemy/cell.rb +33 -35
  57. data/app/models/alchemy/content.rb +20 -111
  58. data/app/models/alchemy/content/factory.rb +188 -0
  59. data/app/models/alchemy/element.rb +51 -200
  60. data/app/models/alchemy/element/definitions.rb +52 -0
  61. data/app/models/alchemy/element/presenters.rb +87 -0
  62. data/app/models/alchemy/essence_date.rb +1 -1
  63. data/app/models/alchemy/essence_file.rb +6 -7
  64. data/app/models/alchemy/essence_picture.rb +19 -4
  65. data/app/models/alchemy/message.rb +18 -14
  66. data/app/models/alchemy/page.rb +120 -214
  67. data/app/models/alchemy/page/elements.rb +145 -36
  68. data/app/models/alchemy/page/natures.rb +90 -0
  69. data/app/models/alchemy/page/scopes.rb +93 -0
  70. data/app/models/alchemy/page/users.rb +25 -0
  71. data/app/models/alchemy/picture.rb +15 -0
  72. data/app/models/alchemy/site.rb +15 -1
  73. data/app/models/alchemy/site/layout.rb +38 -0
  74. data/app/models/alchemy/user.rb +13 -3
  75. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +7 -7
  76. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +8 -8
  77. data/app/views/alchemy/admin/attachments/_tag_list.html.erb +1 -16
  78. data/app/views/alchemy/admin/attachments/destroy.js.erb +1 -4
  79. data/app/views/alchemy/admin/contents/create.js.erb +1 -1
  80. data/app/views/alchemy/admin/dashboard/index.html.erb +14 -13
  81. data/app/views/alchemy/admin/elements/_element_head.html.erb +7 -7
  82. data/app/views/alchemy/admin/elements/_refresh_editor.js.erb +10 -0
  83. data/app/views/alchemy/admin/elements/create.js.erb +44 -44
  84. data/app/views/alchemy/admin/elements/fold.js.erb +22 -26
  85. data/app/views/alchemy/admin/elements/trash.js.erb +1 -1
  86. data/app/views/alchemy/admin/elements/update.js.erb +22 -25
  87. data/app/views/alchemy/admin/essence_files/assign.js.erb +8 -3
  88. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +14 -12
  89. data/app/views/alchemy/admin/essence_pictures/edit.html.erb +22 -39
  90. data/app/views/alchemy/admin/pages/_page.html.erb +73 -80
  91. data/app/views/alchemy/admin/pages/destroy.js.erb +2 -2
  92. data/app/views/alchemy/admin/pages/edit.html.erb +21 -18
  93. data/app/views/alchemy/admin/pages/fold.js.erb +1 -0
  94. data/app/views/alchemy/admin/pages/info.html.erb +32 -0
  95. data/app/views/alchemy/admin/partials/_main_navigation_entry.html.erb +11 -13
  96. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +20 -20
  97. data/app/views/alchemy/admin/partials/_sub_navigation.html.erb +8 -0
  98. data/app/views/alchemy/admin/partials/_toolbar_button.html.erb +25 -0
  99. data/app/views/alchemy/admin/partials/_upload_form.html.erb +15 -15
  100. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +39 -39
  101. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +10 -10
  102. data/app/views/alchemy/admin/pictures/_tag_list.html.erb +1 -16
  103. data/app/views/alchemy/admin/resources/destroy.js.erb +1 -1
  104. data/app/views/alchemy/base/500.html.erb +1 -1
  105. data/app/views/alchemy/base/permission_denied.js.erb +1 -1
  106. data/app/views/alchemy/base/redirect.js.erb +1 -1
  107. data/app/views/alchemy/essences/_essence_link_editor.html.erb +1 -1
  108. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +1 -1
  109. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +1 -1
  110. data/app/views/alchemy/essences/_essence_text_editor.html.erb +1 -1
  111. data/app/views/alchemy/essences/{_essence_picture_tools.html.erb → shared/_essence_picture_tools.html.erb} +5 -5
  112. data/app/views/alchemy/essences/{_linkable_essence_tools.html.erb → shared/_linkable_essence_tools.html.erb} +0 -0
  113. data/app/views/alchemy/messages/contact_form_mail.de.text.erb +12 -0
  114. data/app/views/alchemy/messages/contact_form_mail.en.text.erb +12 -0
  115. data/app/views/alchemy/notifications/reset_password_instructions.de.text.erb +1 -1
  116. data/app/views/alchemy/notifications/reset_password_instructions.en.text.erb +2 -2
  117. data/app/views/alchemy/pages/sitemap.xml.erb +3 -5
  118. data/app/views/alchemy/user_sessions/leave.html.erb +1 -1
  119. data/app/views/layouts/alchemy/admin.html.erb +4 -2
  120. data/app/views/layouts/alchemy/sitemap.xml.erb +1 -1
  121. data/bin/alchemy +7 -13
  122. data/config/alchemy/config.yml +1 -0
  123. data/config/authorization_rules.rb +2 -3
  124. data/config/initializers/dragonfly.rb +2 -0
  125. data/config/locales/alchemy.de.yml +8 -9
  126. data/config/locales/alchemy.en.yml +7 -4
  127. data/config/routes.rb +3 -0
  128. data/db/migrate/{20130214233001_alchemy_two_point_five.rb → 20130827094554_alchemy_two_point_six.rb} +29 -6
  129. data/lib/alchemy/auth/engine.rb +9 -0
  130. data/lib/alchemy/capistrano.rb +37 -12
  131. data/lib/alchemy/config.rb +48 -35
  132. data/lib/alchemy/engine.rb +35 -6
  133. data/lib/alchemy/essence.rb +25 -29
  134. data/lib/alchemy/ferret/search.rb +86 -0
  135. data/lib/alchemy/{scoped_pagination_url_helper.rb → kaminari/scoped_pagination_url_helper.rb} +0 -0
  136. data/lib/alchemy/logger.rb +3 -4
  137. data/lib/alchemy/page_layout.rb +124 -55
  138. data/lib/alchemy/resource.rb +0 -10
  139. data/lib/alchemy/resources_helper.rb +0 -5
  140. data/lib/alchemy/seeder.rb +1 -32
  141. data/lib/alchemy/shell.rb +6 -1
  142. data/lib/alchemy/tinymce.rb +41 -32
  143. data/lib/alchemy/upgrader.rb +3 -1
  144. data/lib/alchemy/upgrader/two_point_five.rb +15 -8
  145. data/lib/alchemy/upgrader/two_point_one.rb +10 -10
  146. data/lib/alchemy/upgrader/two_point_two.rb +96 -51
  147. data/lib/alchemy/version.rb +1 -1
  148. data/lib/alchemy_cms.rb +5 -46
  149. data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +1 -1
  150. data/lib/rails/generators/alchemy/devise/devise_generator.rb +9 -4
  151. data/lib/rails/generators/alchemy/essence/essence_generator.rb +7 -6
  152. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +1 -1
  153. data/lib/rails/generators/alchemy/scaffold/files/_standard.html.erb +1 -0
  154. data/lib/rails/generators/alchemy/scaffold/scaffold_generator.rb +1 -0
  155. data/lib/rails/generators/alchemy/site_layouts/site_layouts_generator.rb +23 -0
  156. data/lib/rails/generators/alchemy/site_layouts/templates/layout.html.erb +1 -0
  157. data/lib/rails/generators/alchemy/site_layouts/templates/layout.html.haml +1 -0
  158. data/lib/rails/generators/alchemy/site_layouts/templates/layout.html.slim +1 -0
  159. data/lib/rails/templates/alchemy.rb +2 -2
  160. data/lib/tasks/alchemy/db.rake +3 -1
  161. data/lib/tasks/alchemy/tidy.rake +82 -0
  162. data/lib/tasks/alchemy/upgrade.rake +2 -1
  163. data/spec/controllers/admin/attachments_controller_spec.rb +124 -0
  164. data/spec/controllers/admin/base_controller_spec.rb +35 -0
  165. data/spec/controllers/admin/clipboard_controller_spec.rb +1 -1
  166. data/spec/controllers/admin/contents_controller_spec.rb +17 -26
  167. data/spec/controllers/admin/dashboard_controller_spec.rb +121 -0
  168. data/spec/controllers/admin/elements_controller_spec.rb +1 -1
  169. data/spec/controllers/admin/essence_files_controller_spec.rb +67 -0
  170. data/spec/controllers/admin/essence_pictures_controller_spec.rb +161 -0
  171. data/spec/controllers/admin/languages_controller_spec.rb +1 -1
  172. data/spec/controllers/admin/layoutpages_controller_spec.rb +28 -0
  173. data/spec/controllers/admin/pages_controller_spec.rb +164 -118
  174. data/spec/controllers/admin/pictures_controller_spec.rb +89 -0
  175. data/spec/controllers/admin/trash_controller_spec.rb +21 -31
  176. data/spec/controllers/admin/users_controller_spec.rb +114 -85
  177. data/spec/controllers/attachments_controller_spec.rb +6 -2
  178. data/spec/controllers/base_controller_spec.rb +22 -0
  179. data/spec/controllers/elements_controller_spec.rb +1 -1
  180. data/spec/controllers/messages_controller_spec.rb +200 -0
  181. data/spec/controllers/pictures_controller_spec.rb +1 -1
  182. data/spec/controllers/user_sessions_controller_spec.rb +7 -6
  183. data/spec/controllers/users_controller_spec.rb +2 -2
  184. data/spec/dummy/config/alchemy/cells.yml +2 -0
  185. data/spec/dummy/config/application.rb +19 -8
  186. data/spec/dummy/db/migrate/{20130214233001_alchemy_two_point_five.rb → 20130827094554_alchemy_two_point_six.rb} +29 -6
  187. data/spec/dummy/db/schema.rb +1 -1
  188. data/spec/fast_specs.rb +15 -0
  189. data/spec/helpers/admin/base_helper_spec.rb +53 -34
  190. data/spec/helpers/admin/contents_helper_spec.rb +15 -7
  191. data/spec/helpers/admin/elements_helper_spec.rb +79 -34
  192. data/spec/helpers/admin/essences_helper_spec.rb +45 -31
  193. data/spec/helpers/admin/navigation_helper_spec.rb +204 -0
  194. data/spec/helpers/admin/pages_helper_spec.rb +25 -15
  195. data/spec/helpers/admin/tags_helper_spec.rb +62 -2
  196. data/spec/helpers/elements_helper_spec.rb +202 -138
  197. data/spec/helpers/pages_helper_spec.rb +48 -0
  198. data/spec/helpers/url_helper_spec.rb +7 -0
  199. data/spec/libraries/config_spec.rb +110 -3
  200. data/spec/libraries/essence_spec.rb +29 -9
  201. data/spec/libraries/page_layout_spec.rb +134 -0
  202. data/spec/libraries/resource_spec.rb +3 -16
  203. data/spec/libraries/resources_helper_spec.rb +4 -8
  204. data/spec/libraries/shell_spec.rb +1 -0
  205. data/spec/libraries/tinymce_spec.rb +61 -0
  206. data/spec/mailers/messages_spec.rb +23 -0
  207. data/spec/models/attachment_spec.rb +45 -0
  208. data/spec/models/cell_spec.rb +62 -9
  209. data/spec/models/content_spec.rb +110 -28
  210. data/spec/models/element_spec.rb +275 -253
  211. data/spec/models/essence_date_spec.rb +25 -0
  212. data/spec/models/essence_file_spec.rb +23 -0
  213. data/spec/models/essence_html_spec.rb +13 -0
  214. data/spec/models/essence_picture_spec.rb +16 -0
  215. data/spec/models/essence_text_spec.rb +29 -0
  216. data/spec/models/language_spec.rb +34 -0
  217. data/spec/models/message_spec.rb +43 -0
  218. data/spec/models/page_spec.rb +726 -567
  219. data/spec/models/picture_spec.rb +98 -0
  220. data/spec/models/site_spec.rb +60 -2
  221. data/spec/models/tag_spec.rb +31 -0
  222. data/spec/models/user_spec.rb +4 -4
  223. data/spec/spec_helper.rb +49 -58
  224. data/spec/support/alchemy/controller_helpers.rb +35 -0
  225. data/spec/support/alchemy/{specs_helpers.rb → integration_helpers.rb} +4 -8
  226. data/spec/{factories.rb → support/factories.rb} +11 -1
  227. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.nestedSortable.js +2 -8
  228. metadata +166 -106
  229. data/Guardfile +0 -16
  230. data/app/assets/javascripts/alchemy/alchemy.dirty.js +0 -93
  231. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js +0 -122
  232. data/app/models/alchemy/tree_node.rb +0 -4
  233. data/app/views/alchemy/admin/pages/_page_infos.html.erb +0 -3
  234. data/app/views/alchemy/admin/partials/_sub_navigation_tab.html.erb +0 -8
  235. data/app/views/alchemy/messages/contact_form_mail.text.erb +0 -12
  236. data/config/initializers/kaminari_config.rb +0 -9
  237. data/db/migrate/20130221200514_migrate_attachments_to_dragonfly.rb +0 -21
  238. data/db/migrate/20130312205327_change_alchemy_users_role_to_roles.rb +0 -11
  239. data/lib/alchemy/auth_engine.rb +0 -7
  240. data/lib/alchemy/authentication_helpers.rb +0 -9
  241. data/lib/alchemy/ferret_search.rb +0 -84
  242. data/lib/extensions/array.rb +0 -25
  243. data/lib/extensions/hash.rb +0 -34
  244. data/spec/dummy/db/migrate/20130221200514_migrate_attachments_to_dragonfly.rb +0 -21
  245. data/spec/dummy/db/migrate/20130312205327_change_alchemy_users_role_to_roles.rb +0 -11
  246. data/spec/models/page_layout_spec.rb +0 -60
@@ -0,0 +1,9 @@
1
+ module Alchemy
2
+ module Auth
3
+ module Engine
4
+ def self.get_instance
5
+ ::Authorization::Engine.instance
6
+ end
7
+ end
8
+ end
9
+ end
@@ -83,9 +83,10 @@ EOF
83
83
  run "cd #{current_path} && #{rake} RAILS_ENV=#{fetch(:rails_env, 'production')} alchemy:db:seed"
84
84
  end
85
85
 
86
- desc "Dumps the database into 'db/dumps'"
86
+ desc "Dumps the database into 'db/dumps' on the server."
87
87
  task :dump, :roles => :db do
88
- run "cd #{current_path} && #{rake} RAILS_ENV=#{fetch(:rails_env, 'production')} alchemy:db:dump"
88
+ timestamp = Time.now.strftime('%Y-%m-%d-%H-%M')
89
+ run "cd #{current_path} && mkdir -p db/dumps && #{rake} RAILS_ENV=#{fetch(:rails_env, 'production')} DUMP_FILENAME=db/dumps/#{timestamp}.sql alchemy:db:dump"
89
90
  end
90
91
 
91
92
  end
@@ -101,17 +102,14 @@ EOF
101
102
 
102
103
  desc "Imports the database into your local development machine."
103
104
  task :database, :roles => [:db], :only => {:primary => true} do
105
+ require 'spinner'
104
106
  server = find_servers_for_task(current_task).first
105
- dump_cmd = "cd #{current_path} && #{rake} RAILS_ENV=#{fetch(:rails_env, 'production')} alchemy:db:dump"
106
- sql_stream = "ssh -p #{fetch(:port, 22)} #{user}@#{server} '#{dump_cmd}'"
107
- mysql_credentials = ["--user='#{database_config['username']}'"]
108
- if database_config['password']
109
- mysql_credentials << "--password='#{database_config['password']}'"
110
- end
111
- if host = database_config['host'] && host != 'localhost'
112
- mysql_credentials << "--host='#{host}'"
107
+ spinner = Spinner.new
108
+ print "\n"
109
+ spinner.task("Importing the database. Please wait...") do
110
+ system db_import_cmd(server)
113
111
  end
114
- system "#{sql_stream} | mysql #{mysql_credentials.join(' ')} #{database_config['database']}"
112
+ spinner.spin!
115
113
  end
116
114
 
117
115
  desc "Imports attachments into your local machine using rsync."
@@ -136,7 +134,34 @@ EOF
136
134
 
137
135
  def database_config
138
136
  raise "database.yml not found!" if !File.exists?("./config/database.yml")
139
- YAML.load_file("./config/database.yml").fetch(ENV['RAILS_ENV'] || 'development')
137
+ @database_config ||= begin
138
+ config_file = YAML.load_file("./config/database.yml")
139
+ if config = config_file.fetch(ENV['RAILS_ENV'] || 'development')
140
+ config
141
+ else
142
+ raise "Database configuration for #{ENV['RAILS_ENV'] || 'development'} not found!"
143
+ end
144
+ end
145
+ end
146
+
147
+ def db_import_cmd(server)
148
+ dump_cmd = "cd #{current_path} && #{rake} RAILS_ENV=#{fetch(:rails_env, 'production')} alchemy:db:dump"
149
+ sql_stream = "ssh -p #{fetch(:port, 22)} #{user}@#{server} '#{dump_cmd}'"
150
+ "#{sql_stream} | mysql #{mysql_credentials} #{database_config['database']}"
151
+ end
152
+
153
+ def mysql_credentials
154
+ mysql_credentials = []
155
+ if database_config['username']
156
+ mysql_credentials << "--user='#{database_config['username']}'"
157
+ end
158
+ if database_config['password']
159
+ mysql_credentials << "--password='#{database_config['password']}'"
160
+ end
161
+ if (host = database_config['host']) && (host != 'localhost')
162
+ mysql_credentials << "--host='#{host}'"
163
+ end
164
+ mysql_credentials.join(' ')
140
165
  end
141
166
 
142
167
  end
@@ -1,51 +1,64 @@
1
+ # encoding: utf-8
2
+
1
3
  module Alchemy
2
4
  class Config
3
5
 
4
6
  class << self
5
7
 
6
- # Returns the configuration for given parameter name from +config/alchemy/config.yml+ file.
8
+ # Returns the configuration for given parameter name.
9
+ #
10
+ # @param name [String]
11
+ #
7
12
  def get(name)
8
13
  show[name.to_s]
9
14
  end
10
-
11
15
  alias_method :parameter, :get
12
16
 
13
- # Returns the complete configuration from +config/alchemy/config.yml+ file.
17
+ # Returns a merged configuration of the following files
18
+ #
19
+ # Alchemy´s default config: +gems/../alchemy_cms/config/alchemy/config.yml+
20
+ # Your apps default config: +your_app/config/alchemy/config.yml+
21
+ # Environment specific config: +your_app/config/alchemy/development.config.yml+
22
+ #
23
+ # An environment specific config overwrites the settings of your apps default config,
24
+ # while your apps default config has precedence over Alchemy´s default config.
25
+ #
14
26
  def show
15
- @@config ||= read_files
27
+ @config ||= merge_configs!(alchemy_config, main_app_config, env_specific_config)
28
+ end
29
+
30
+ private
31
+
32
+ # Alchemy default configuration
33
+ def alchemy_config
34
+ read_file(File.join(File.dirname(__FILE__), '..', '..', 'config/alchemy/config.yml'))
35
+ end
36
+
37
+ # Application specific configuration
38
+ def main_app_config
39
+ read_file("#{Rails.root}/config/alchemy/config.yml")
40
+ end
41
+
42
+ # Rails Environment specific configuration
43
+ def env_specific_config
44
+ read_file("#{Rails.root}/config/alchemy/#{Rails.env}.config.yml")
45
+ end
46
+
47
+ # Tries to load yaml file from given path.
48
+ # If it does not exist, or its empty, it returns an empty Hash.
49
+ #
50
+ def read_file(file)
51
+ return YAML.load_file(file) || {} if File.exists?(file) # YAML.load_file returns false if file is empty.
52
+ {}
16
53
  end
17
54
 
18
- private
19
-
20
- def read_files
21
- # Looking for any Rails Environment specific configuration
22
- if File.exists? "#{Rails.root.to_s}/config/alchemy/config_#{Rails.env}.yml"
23
- config_1 = YAML.load_file("#{Rails.root.to_s}/config/alchemy/config_#{Rails.env}.yml")
24
- else
25
- config_1 = {}
26
- end
27
-
28
- # Looking for Application specific configuration
29
- if File.exists? "#{Rails.root.to_s}/config/alchemy/config.yml"
30
- config_2 = YAML.load_file("#{Rails.root.to_s}/config/alchemy/config.yml")
31
- else
32
- config_2 = {}
33
- end
34
-
35
- # Reading Alchemy standard configuration
36
- if File.exists? File.join(File.dirname(__FILE__), '..', '..', 'config/alchemy/config.yml')
37
- config_3 = YAML.load_file(File.join(File.dirname(__FILE__), '..', '..', 'config/alchemy/config.yml'))
38
- else
39
- config_3 = {}
40
- end
41
-
42
- # Mergin all together
43
- if config_1.blank? && config_3.blank? && config_3.blank?
44
- raise LoadError, 'No Alchemy config file found!'
45
- else
46
- [config_1, config_2, config_3].map(&:stringify_keys!)
47
- return config_3.merge(config_2.merge(config_1))
48
- end
55
+ # Merges all given configs together
56
+ #
57
+ def merge_configs!(*config_files)
58
+ raise LoadError, 'No Alchemy config file found!' if config_files.map(&:blank?).all?
59
+ config = {}
60
+ config_files.each {|h| config.merge!(h.stringify_keys!) }
61
+ config
49
62
  end
50
63
 
51
64
  end
@@ -1,5 +1,38 @@
1
+ # Require globally used external libraries
2
+ require 'coffee-rails'
3
+ require 'compass-rails'
4
+ require 'declarative_authorization'
5
+ require 'devise'
6
+ require 'dynamic_form'
7
+ require 'jquery-rails'
8
+ require 'jquery-ui-rails'
9
+ require 'kaminari'
10
+ require 'rails3-jquery-autocomplete'
11
+ require 'sass-rails'
12
+ require 'sassy-buttons'
13
+
14
+ # Require globally used Alchemy mixins
15
+ require 'alchemy/auth/engine'
16
+ require 'alchemy/config'
17
+ require 'alchemy/errors'
18
+ require 'alchemy/essence'
19
+ require 'alchemy/ferret/search'
20
+ require 'alchemy/filetypes'
21
+ require 'alchemy/i18n'
22
+ require 'alchemy/logger'
23
+ require 'alchemy/modules'
24
+ require 'alchemy/mount_point'
25
+ require 'alchemy/name_conversions'
26
+ require 'alchemy/page_layout'
27
+ require 'alchemy/picture_attributes'
28
+ require 'alchemy/tinymce'
29
+
30
+ # Require hacks
31
+ require 'alchemy/kaminari/scoped_pagination_url_helper'
32
+ require File.join(File.dirname(__FILE__), '../extensions/action_view')
33
+
34
+ # Require middleware
1
35
  require File.join(File.dirname(__FILE__), '../middleware/flash_session_cookie')
2
- require File.join(File.dirname(__FILE__), 'authentication_helpers')
3
36
 
4
37
  module Alchemy
5
38
  class Engine < Rails::Engine
@@ -37,11 +70,7 @@ module Alchemy
37
70
  end
38
71
 
39
72
  initializer "alchemy.add_authorization_rules" do
40
- Alchemy::AuthEngine.get_instance.load(File.join(File.dirname(__FILE__), '../..', 'config/authorization_rules.rb'))
41
- end
42
-
43
- config.after_initialize do
44
- #ApplicationController.send :include, Alchemy::AuthenticationHelpers
73
+ Alchemy::Auth::Engine.get_instance.load(File.join(File.dirname(__FILE__), '../..', 'config/authorization_rules.rb'))
45
74
  end
46
75
 
47
76
  end
@@ -7,23 +7,26 @@ module Alchemy #:nodoc:
7
7
  end
8
8
 
9
9
  # Delivers various methods we need for Essences in Alchemy.
10
+ #
10
11
  # To turn a model into an essence call acts_as_essence inside your model and you will get:
11
12
  # * validations
12
13
  # * several getters (ie: page, element, content, ingredient, preview_text)
14
+ #
13
15
  module ClassMethods
14
16
 
15
- # Configuration options are:
17
+ # Turn any active record model into an essence by calling this class method
18
+ #
19
+ # @option options [String || Symbol] ingredient_column ('body')
20
+ # specifies the column name you use for storing the content in the database (default: +body+)
21
+ # @option options [String || Symbol] validate_column (ingredient_column)
22
+ # The column the the validations run against.
23
+ # @option options [String || Symbol] preview_text_column (ingredient_column)
24
+ # Specify the column for the preview_text method.
16
25
  #
17
- # * +ingredient_column+ - specifies the column name you use for storing the content in the database (default: +body+)
18
- # * +validate_column+ - which column should be validated. (default: ingredient_column)
19
- # * +preview_text_column+ - specifies the column for the preview_text method. (default: ingredient_column)
20
- # * +preview_text_method+ - a method called on ingredient to get the preview text. (default: ingredient_column)
21
26
  def acts_as_essence(options={})
22
- configuration = {}
23
- configuration.update(options) if options.is_a?(Hash)
24
- ingredient_column = configuration[:ingredient_column].blank? ? 'body' : configuration[:ingredient_column]
25
- preview_text_column = configuration[:preview_text_column].blank? ? ingredient_column : configuration[:preview_text_column]
26
- validate_column = configuration[:validate_column].blank? ? ingredient_column : configuration[:validate_column]
27
+ configuration = {
28
+ ingredient_column: 'body'
29
+ }.update(options)
27
30
 
28
31
  class_eval <<-EOV
29
32
  attr_accessor :validation_errors
@@ -39,22 +42,17 @@ module Alchemy #:nodoc:
39
42
  #{self.name}
40
43
  end
41
44
 
42
- def validation_column
43
- '#{validate_column}'
44
- end
45
-
46
45
  def ingredient_column
47
- '#{ingredient_column}'
46
+ '#{configuration[:ingredient_column]}'
48
47
  end
49
48
 
50
- def preview_text_column
51
- '#{preview_text_column}'
49
+ def validation_column
50
+ '#{configuration[:validate_column] || configuration[:ingredient_column]}'
52
51
  end
53
52
 
54
- def preview_text_method
55
- '#{configuration[:preview_text_method]}'
53
+ def preview_text_column
54
+ '#{configuration[:preview_text_column] || configuration[:ingredient_column]}'
56
55
  end
57
-
58
56
  EOV
59
57
  end
60
58
 
@@ -65,10 +63,12 @@ module Alchemy #:nodoc:
65
63
  # Essence Validations:
66
64
  #
67
65
  # Essence validations can be set inside the config/elements.yml file.
66
+ #
68
67
  # Currently supported validations are:
69
- # * presence
70
- # * format
71
- # * uniqueness
68
+ #
69
+ # * presence
70
+ # * format
71
+ # * uniqueness
72
72
  #
73
73
  # If you want to validate the format you must additionally pass validate_format_as or validate_format_with:
74
74
  #
@@ -171,13 +171,9 @@ module Alchemy #:nodoc:
171
171
  end
172
172
 
173
173
  # Returns the first x (default 30) characters of ingredient for the Element#preview_text method.
174
+ #
174
175
  def preview_text(maxlength = 30)
175
- if preview_text_method.blank?
176
- self.send(preview_text_column).to_s[0..maxlength]
177
- else
178
- return "" if ingredient.blank?
179
- ingredient.send(preview_text_method).to_s[0..maxlength]
180
- end
176
+ self.send(preview_text_column).to_s[0..maxlength-1]
181
177
  end
182
178
 
183
179
  def open_link_in_new_window?
@@ -0,0 +1,86 @@
1
+ module Alchemy
2
+ # Provides full text search methods in your controller
3
+ #
4
+ # === Usage
5
+ #
6
+ # include Alchemy::Ferret::Search
7
+ #
8
+ module Ferret
9
+ module Search
10
+
11
+ # Adds a +before_filter+ to your controller
12
+ #
13
+ def self.included(controller)
14
+ controller.send(:before_filter, :perform_search, :only => :show)
15
+ controller.send(:helper_method, :find_search_result_page)
16
+ end
17
+
18
+ # Performs a full text search with +Ferret+.
19
+ #
20
+ # Gets invoked everytime 'query' is given in params.
21
+ #
22
+ # This method only sets the +@search_results+ instance variable.
23
+ #
24
+ # You have to redirect to the search result page within a search form.
25
+ #
26
+ # === Alchemy provides a handy helper for rendering the search form:
27
+ #
28
+ # render_search_form
29
+ #
30
+ # === Note
31
+ #
32
+ # If in preview mode a fake search value "lorem" will be set.
33
+ #
34
+ # @see Alchemy::PagesHelper#render_search_form
35
+ #
36
+ def perform_search
37
+ if @preview_mode && params[:query].blank?
38
+ params[:query] = 'lorem'
39
+ end
40
+ return if params[:query].blank?
41
+ @search_results = get_search_results
42
+ end
43
+
44
+ # Finds what is provided in "query" param with Ferret on EssenceText and EssenceRichtext
45
+ #
46
+ # @return [Array]
47
+ #
48
+ def get_search_results
49
+ search_results = []
50
+ %w(Alchemy::EssenceText Alchemy::EssenceRichtext).each do |e|
51
+ search_results += e.constantize.includes(:contents => {:element => :page}).find_with_ferret(
52
+ "*#{params[:query]}*",
53
+ {:limit => :all},
54
+ {:conditions => [
55
+ 'alchemy_pages.public = ? AND alchemy_pages.layoutpage = ? AND alchemy_pages.restricted = ? AND alchemy_pages.language_id = ?',
56
+ true, false, false, session[:language_id]
57
+ ]}
58
+ )
59
+ end
60
+ if search_results.any?
61
+ search_results.sort { |y, x| x.ferret_score <=> y.ferret_score }
62
+ end
63
+ end
64
+
65
+ # A view helper that loads the search result page.
66
+ #
67
+ # === Raises a ActiveRecord::RecordNotFound error, if the page could not be found or is not published.
68
+ #
69
+ # @return [Alchemy::Page]
70
+ #
71
+ def find_search_result_page
72
+ if searchresult_page_layout = PageLayout.get_all_by_attributes(:searchresults => true).first
73
+ search_result_page = Page.published.where(
74
+ :page_layout => searchresult_page_layout["name"],
75
+ :language_id => session[:language_id]
76
+ ).limit(1).first
77
+ end
78
+ if search_result_page.nil?
79
+ logger.warn "\n++++++\nNo published search result page found. Please create one or publish your search result page.\n++++++\n"
80
+ end
81
+ search_result_page
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -1,16 +1,15 @@
1
1
  module Alchemy
2
2
  module Logger
3
3
 
4
- # Logs a warning to the Rails standard logger and adds some nicer formatting
4
+ # Logs a debug message to the Rails standard logger and adds some nicer formatting
5
5
  def self.warn(message, caller_string)
6
- Rails.logger.warn %(\n++++ WARNING: #{message}\nCalled from: #{caller_string}\n)
6
+ Rails.logger.debug %(\n++++ WARNING: #{message}\nCalled from: #{caller_string}\n)
7
7
  return nil
8
8
  end
9
9
 
10
- def warn(message)
10
+ def log_warning(message)
11
11
  Alchemy::Logger.warn(message, caller.first)
12
12
  end
13
- alias_method :warning, :warn
14
13
 
15
14
  end
16
15
  end
@@ -2,40 +2,41 @@ module Alchemy
2
2
  class PageLayout
3
3
  class << self
4
4
 
5
- def element_names_for(page_layout)
6
- layout_description = get(page_layout)
7
- if layout_description.blank?
8
- puts "\n+++ Warning: No Layout Description for #{page_layout} found! in page_layouts.yml\n"
9
- return []
10
- else
11
- layout_description["elements"] || []
12
- end
13
- end
14
-
15
- # Returns all layouts defined in +config/alchemy/page_layout.yml+.
5
+ # Returns all page layouts.
6
+ #
7
+ # They are defined in +config/alchemy/page_layout.yml+ file.
8
+ #
16
9
  def all
17
- @@definitions = read_layouts_file
10
+ @definitions ||= read_layouts_file
18
11
  end
19
12
 
20
- # Add additional pagelayout definitions. I.E. from your module.
21
- # Call +Alchemy::PageLayout.add(your_layout_definition)+ in your engine.rb file.
22
- # You can pass a single layout definition as Hash, or a collection of pagelayouts as Array.
23
- # Example Pagelayout definitions can be found in the +page_layouts.yml+ from the standard set.
13
+ # Add additional page layout definitions to collection.
14
+ #
15
+ # Useful for extending the page layouts from an Alchemy module.
16
+ #
17
+ # === Usage Example
18
+ #
19
+ # Call +Alchemy::PageLayout.add(your_layout_definition)+ in your engine.rb file.
20
+ #
21
+ # @param [Array || Hash]
22
+ # You can pass a single layout definition as Hash, or a collection of page layouts as Array.
23
+ #
24
24
  def add(page_layout)
25
25
  all
26
26
  if page_layout.is_a?(Array)
27
- @@definitions += page_layout
27
+ @definitions += page_layout
28
28
  elsif page_layout.is_a?(Hash)
29
- @@definitions << page_layout
29
+ @definitions << page_layout
30
30
  else
31
31
  raise TypeError
32
32
  end
33
33
  end
34
34
 
35
- # Returns the page_layout description found by name in page_layouts.yml
35
+ # Returns one page layout description by given name.
36
+ #
36
37
  def get(name)
37
38
  return {} if name.blank?
38
- all.detect { |a| a["name"].downcase == name.downcase }
39
+ all.detect { |a| a['name'].downcase == name.downcase }
39
40
  end
40
41
 
41
42
  def get_all_by_attributes(attributes)
@@ -53,60 +54,128 @@ module Alchemy
53
54
  end
54
55
 
55
56
  # Returns page layouts ready for Rails' select form helper.
56
- def layouts_for_select(language_id, layoutpage = false)
57
- map_layouts(selectable_layouts(language_id, layoutpage), [[I18n.t('Please choose'), '']])
57
+ #
58
+ def layouts_for_select(language_id, only_layoutpages = false)
59
+ @map_array = [[I18n.t('Please choose'), '']]
60
+ mapped_layouts_for_select(selectable_layouts(language_id, only_layoutpages))
58
61
  end
59
62
 
60
- def layouts_with_own_for_select(own_layout, language_id, layoutpage)
61
- layouts = selectable_layouts(language_id, layoutpage)
62
- if layouts.detect { |l| l['name'] == own_layout } == nil
63
- map_array = [
64
- [I18n.t(own_layout, scope: 'page_layout_names', default: own_layout.to_s.humanize), own_layout]
65
- ]
63
+ # Returns page layouts including given layout ready for Rails' select form helper.
64
+ #
65
+ def layouts_with_own_for_select(page_layout_name, language_id, only_layoutpages = false)
66
+ layouts = selectable_layouts(language_id, only_layoutpages)
67
+ if layouts.detect { |l| l['name'] == page_layout_name }.nil?
68
+ @map_array = [[human_layout_name(page_layout_name), page_layout_name]]
66
69
  else
67
- map_array = []
68
- end
69
- map_layouts(layouts, map_array)
70
- end
71
-
72
- # Maps given layouts for Rails select form helper.
73
- def map_layouts(layouts, map_array = [])
74
- layouts.each do |layout|
75
- map_array << [
76
- I18n.t(layout['name'], scope: 'page_layout_names', default: layout['name'].to_s.humanize),
77
- layout["name"]
78
- ]
70
+ @map_array = []
79
71
  end
80
- map_array
72
+ mapped_layouts_for_select(layouts)
81
73
  end
82
74
 
83
- def selectable_layouts(language_id, layoutpage = false)
84
- all.select do |layout|
85
- next if layout["hide"]
86
- used = layout["unique"] && has_a_page_this_layout?(layout["name"], language_id)
87
- if layoutpage
88
- layout["layoutpage"] == true && !used
75
+ # Returns all layouts that can be used for creating a new page.
76
+ #
77
+ # It removes all layouts from available layouts that are unique and already taken and that are marked as hide.
78
+ #
79
+ # @param [Fixnum]
80
+ # language_id of current used Language.
81
+ # @param [Boolean] (false)
82
+ # Pass true to only select layouts for global/layout pages.
83
+ #
84
+ def selectable_layouts(language_id, only_layoutpages = false)
85
+ @language_id = language_id
86
+ all.select { |layout|
87
+ if only_layoutpages
88
+ layout['layoutpage'] && layout_available?(layout)
89
89
  else
90
- layout["layoutpage"] != true && !used
90
+ !layout['layoutpage'] && layout_available?(layout)
91
91
  end
92
+ }
93
+ end
94
+
95
+ # Returns all names of elements defined in given page layout.
96
+ #
97
+ def element_names_for(page_layout)
98
+ if layout_description = get(page_layout)
99
+ layout_description.fetch('elements', [])
100
+ else
101
+ Rails.logger.warn "\n+++ Warning: No Layout Description for #{page_layout} found! in page_layouts.yml\n"
102
+ return []
92
103
  end
93
104
  end
94
105
 
95
- def has_a_page_this_layout?(layout, language_id)
96
- Page.where({:page_layout => layout, :language_id => language_id}).any?
106
+ # Translates name for given layout
107
+ #
108
+ # === Translation example
109
+ #
110
+ # de:
111
+ # alchemy:
112
+ # page_layout_names:
113
+ # products_overview: Produktübersicht
114
+ #
115
+ # @param [String]
116
+ # The layout name
117
+ #
118
+ def human_layout_name(layout)
119
+ I18n.t(layout, scope: 'page_layout_names', default: layout.to_s.humanize)
97
120
  end
98
121
 
99
122
  private
100
123
 
124
+ # Returns true if the given layout is unique and not already taken or it should be hidden.
125
+ #
126
+ def layout_available?(layout)
127
+ !layout['hide'] && !already_taken?(layout) && available_on_site?(layout)
128
+ end
129
+
130
+ # Returns true if this layout is unique and already taken by another page.
131
+ #
132
+ def already_taken?(layout)
133
+ layout['unique'] && page_with_layout_existing?(layout['name'])
134
+ end
135
+
136
+ # Returns true if one page already has the given layout
137
+ #
138
+ def page_with_layout_existing?(layout)
139
+ Page.where(page_layout: layout, language_id: @language_id).pluck(:id).any?
140
+ end
141
+
142
+ # Returns true if given layout is available for current site.
143
+ #
144
+ # If no site layouts are defined it always returns true.
145
+ #
146
+ # == Example
147
+ #
148
+ # # config/alchemy/site_layouts.yml
149
+ # - name: default_site
150
+ # page_layouts: [default_intro]
151
+ #
152
+ def available_on_site?(layout)
153
+ Site.current.layout_definition.blank? || Site.current.layout_definition.fetch('page_layouts', []).include?(layout['name'])
154
+ end
155
+
101
156
  # Reads the layout definitions from +config/alchemy/page_layouts.yml+.
157
+ #
102
158
  def read_layouts_file
103
- if File.exists? "#{Rails.root}/config/alchemy/page_layouts.yml"
104
- layouts = YAML.load_file "#{Rails.root}/config/alchemy/page_layouts.yml"
105
- # Since YAML returns false for an empty file, we have to normalize it here.
106
- layouts || []
159
+ if File.exists?(layouts_file_path)
160
+ YAML.load_file(layouts_file_path) || []
107
161
  else
108
- raise LoadError, "Could not find page_layouts.yml file! Please run: rails generate alchemy:scaffold"
162
+ raise LoadError, "Could not find page_layouts.yml file! Please run `rails generate alchemy:scaffold`"
163
+ end
164
+ end
165
+
166
+ # Returns the page_layouts.yml file path
167
+ #
168
+ def layouts_file_path
169
+ Rails.root.join 'config/alchemy/page_layouts.yml'
170
+ end
171
+
172
+ # Maps given layouts for Rails select form helper.
173
+ #
174
+ def mapped_layouts_for_select(layouts)
175
+ layouts.each do |layout|
176
+ @map_array << [human_layout_name(layout['name']), layout["name"]]
109
177
  end
178
+ @map_array
110
179
  end
111
180
 
112
181
  end