alchemy_cms 2.3.2 → 2.4.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. data/.gitignore +1 -2
  2. data/.travis.yml +1 -5
  3. data/Gemfile +4 -4
  4. data/README.md +22 -15
  5. data/alchemy_cms.gemspec +38 -38
  6. data/app/assets/javascripts/alchemy/alchemy.base.js +2 -2
  7. data/app/assets/javascripts/alchemy/alchemy.buttons.js.coffee +31 -0
  8. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js +1 -1
  9. data/app/assets/javascripts/alchemy/alchemy.elements_window.js +24 -15
  10. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +9 -3
  11. data/app/assets/javascripts/alchemy/alchemy.jquery_loader.js +2 -2
  12. data/app/assets/javascripts/alchemy/alchemy.js +1 -0
  13. data/app/assets/javascripts/alchemy/alchemy.menubar.js +4 -12
  14. data/app/assets/javascripts/alchemy/alchemy.onload.js.coffee +32 -0
  15. data/app/assets/javascripts/alchemy/alchemy.windows.js +4 -4
  16. data/app/assets/stylesheets/alchemy/_defaults.scss +0 -1
  17. data/app/assets/stylesheets/alchemy/alchemy.css +2 -1
  18. data/app/assets/stylesheets/alchemy/base.css.scss +2 -54
  19. data/app/assets/stylesheets/alchemy/elements.css.scss +8 -5
  20. data/app/assets/stylesheets/alchemy/errors.css.scss +51 -0
  21. data/app/assets/stylesheets/alchemy/flash.css.scss +0 -2
  22. data/app/assets/stylesheets/alchemy/form_elements.css.scss +31 -75
  23. data/app/assets/stylesheets/alchemy/icons.css.scss +5 -5
  24. data/app/assets/stylesheets/alchemy/menubar.css.scss +0 -2
  25. data/app/assets/stylesheets/alchemy/sitemap.css.scss +0 -1
  26. data/app/assets/stylesheets/alchemy/tables.css.scss +3 -1
  27. data/app/controllers/alchemy/admin/base_controller.rb +19 -12
  28. data/app/controllers/alchemy/admin/elements_controller.rb +52 -24
  29. data/app/controllers/alchemy/admin/pages_controller.rb +11 -5
  30. data/app/controllers/alchemy/admin/resources_controller.rb +3 -4
  31. data/app/controllers/alchemy/admin/users_controller.rb +1 -0
  32. data/app/controllers/alchemy/base_controller.rb +34 -8
  33. data/app/controllers/alchemy/pictures_controller.rb +16 -1
  34. data/app/controllers/alchemy/user_sessions_controller.rb +6 -1
  35. data/app/helpers/alchemy/base_helper.rb +14 -0
  36. data/app/helpers/alchemy/elements_helper.rb +10 -5
  37. data/app/helpers/alchemy/pages_helper.rb +1 -2
  38. data/app/helpers/alchemy/url_helper.rb +43 -24
  39. data/app/models/alchemy/element.rb +23 -16
  40. data/app/models/alchemy/page.rb +25 -14
  41. data/app/models/alchemy/picture.rb +24 -0
  42. data/app/views/alchemy/admin/contents/create.js.erb +1 -1
  43. data/app/views/alchemy/admin/elements/_new_element_form.html.erb +1 -1
  44. data/app/views/alchemy/admin/elements/create.js.erb +11 -3
  45. data/app/views/alchemy/admin/elements/fold.js.erb +1 -1
  46. data/app/views/alchemy/admin/elements/new.html.erb +1 -1
  47. data/app/views/alchemy/admin/elements/update.js.erb +1 -1
  48. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +1 -1
  49. data/app/views/alchemy/admin/languages/_form.html.erb +1 -1
  50. data/app/views/alchemy/admin/pages/_new_page_form.html.erb +1 -1
  51. data/app/views/alchemy/admin/pages/_page.html.erb +1 -1
  52. data/app/views/alchemy/admin/pages/configure.html.erb +10 -6
  53. data/app/views/alchemy/admin/pages/configure_external.html.erb +1 -1
  54. data/app/views/alchemy/admin/pages/edit.html.erb +1 -2
  55. data/app/views/alchemy/admin/pages/new.html.erb +2 -2
  56. data/app/views/alchemy/admin/pages/update.js.erb +10 -2
  57. data/app/views/alchemy/admin/partials/_sub_navigation_tab.html.erb +5 -5
  58. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +2 -1
  59. data/app/views/alchemy/admin/pictures/_picture.html.erb +2 -2
  60. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +2 -1
  61. data/app/views/alchemy/admin/pictures/show_in_window.html.erb +3 -2
  62. data/app/views/alchemy/admin/resources/_form.html.erb +1 -1
  63. data/app/views/alchemy/admin/users/_table.html.erb +4 -4
  64. data/app/views/alchemy/admin/users/edit.html.erb +1 -1
  65. data/app/views/alchemy/admin/users/new.html.erb +1 -1
  66. data/app/views/alchemy/base/error_notice.js.erb +1 -1
  67. data/app/views/alchemy/base/remote_errors.js.erb +2 -3
  68. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +10 -7
  69. data/app/views/alchemy/essences/_essence_picture_view.html.erb +24 -21
  70. data/app/views/layouts/alchemy/admin.html.erb +9 -31
  71. data/bin/alchemy +20 -24
  72. data/config/alchemy/config.yml +6 -0
  73. data/config/alchemy/page_layouts.yml +2 -0
  74. data/config/authorization_rules.rb +1 -1
  75. data/config/locales/alchemy.de.yml +3 -0
  76. data/config/locales/alchemy.en.yml +4 -1
  77. data/db/migrate/20121026100815_alchemy_two_point_three.rb +312 -0
  78. data/lib/alchemy/mount_point.rb +9 -3
  79. data/lib/alchemy/page_layout.rb +89 -73
  80. data/lib/alchemy/version.rb +1 -1
  81. data/lib/rails/generators/alchemy/deploy_script/deploy_script_generator.rb +45 -12
  82. data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +3 -1
  83. data/lib/rails/generators/alchemy/essence/essence_generator.rb +51 -0
  84. data/lib/rails/generators/alchemy/essence/templates/editor.html.erb +18 -0
  85. data/lib/rails/generators/alchemy/essence/templates/view.html.erb +2 -0
  86. data/lib/rails/templates/alchemy.rb +1 -1
  87. data/lib/tasks/install.rake +57 -2
  88. data/spec/controllers/admin/elements_controller_spec.rb +170 -22
  89. data/spec/controllers/admin/trash_controller_spec.rb +1 -1
  90. data/spec/controllers/admin/users_controller_spec.rb +36 -0
  91. data/spec/controllers/base_controller_spec.rb +12 -1
  92. data/spec/controllers/elements_controller_spec.rb +17 -13
  93. data/spec/controllers/pictures_controller_spec.rb +4 -4
  94. data/spec/dummy/config/application.rb +1 -1
  95. data/spec/dummy/db/migrate/20121026100815_alchemy_two_point_three.rb +312 -0
  96. data/spec/dummy/db/migrate/20121026104128_create_events.rb +19 -0
  97. data/spec/dummy/db/schema.rb +1 -1
  98. data/spec/factories.rb +0 -1
  99. data/spec/helpers/base_helper_spec.rb +48 -0
  100. data/spec/helpers/elements_helper_spec.rb +14 -3
  101. data/spec/helpers/url_helper_spec.rb +8 -3
  102. data/spec/integration/picture_security_spec.rb +35 -0
  103. data/spec/integration/translation_integration_spec.rb +6 -5
  104. data/spec/models/element_spec.rb +5 -5
  105. data/spec/models/page_layout_spec.rb +10 -16
  106. data/spec/models/page_spec.rb +25 -2
  107. data/spec/models/picture_spec.rb +24 -2
  108. data/spec/routing_spec.rb +115 -115
  109. data/spec/support/alchemy/specs_helpers.rb +4 -4
  110. data/{app/assets/images/alchemy → vendor/assets/images}/Jcrop.gif +0 -0
  111. data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +19 -243
  112. data/vendor/assets/javascripts/jquery_plugins/jquery.selectboxit.min.js +1 -0
  113. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js +6 -6
  114. data/vendor/assets/stylesheets/jquery.Jcrop.min.css +28 -0
  115. metadata +48 -82
  116. data/app/assets/javascripts/alchemy/alchemy.buttons.js +0 -50
  117. data/app/assets/stylesheets/alchemy/jquery.Jcrop.css.scss +0 -54
  118. data/app/helpers/alchemy/pictures_helper.rb +0 -19
  119. data/db/migrate/20100607143125_create_pages.rb +0 -34
  120. data/db/migrate/20100607144254_create_elements.rb +0 -20
  121. data/db/migrate/20100607145256_create_contents.rb +0 -18
  122. data/db/migrate/20100607145719_create_users.rb +0 -32
  123. data/db/migrate/20100607150611_create_pictures.rb +0 -16
  124. data/db/migrate/20100607150812_create_attachments.rb +0 -16
  125. data/db/migrate/20100607153647_create_folded_pages.rb +0 -13
  126. data/db/migrate/20100607161345_create_essence_texts.rb +0 -19
  127. data/db/migrate/20100607162339_create_elements_pages.rb +0 -12
  128. data/db/migrate/20100607193638_create_essence_pictures.rb +0 -23
  129. data/db/migrate/20100607193646_create_essence_richtexts.rb +0 -16
  130. data/db/migrate/20100607193653_create_essence_htmls.rb +0 -13
  131. data/db/migrate/20100609111653_create_essence_dates.rb +0 -13
  132. data/db/migrate/20100609111809_create_essence_files.rb +0 -15
  133. data/db/migrate/20100609111821_create_essence_flashes.rb +0 -16
  134. data/db/migrate/20100609111837_create_essence_videos.rb +0 -18
  135. data/db/migrate/20100616150753_create_essence_audios.rb +0 -17
  136. data/db/migrate/20100812085225_add_crop_from_and_crop_size_to_essence_pictures.rb +0 -11
  137. data/db/migrate/20100909140701_change_essence_htmls_source_column_type.rb +0 -9
  138. data/db/migrate/20101109150312_alter_pages_visible_column_default.rb +0 -9
  139. data/db/migrate/20101109151812_create_languages.rb +0 -19
  140. data/db/migrate/20101216151419_add_language_id_to_pages.rb +0 -27
  141. data/db/migrate/20101216155216_add_index_to_languages.rb +0 -9
  142. data/db/migrate/20101216173323_add_default_to_languages.rb +0 -9
  143. data/db/migrate/20101218130049_add_urlname_index_to_pages.rb +0 -9
  144. data/db/migrate/20110115123343_remove_css_class_default_from_essence_pictures.rb +0 -11
  145. data/db/migrate/20110224105120_change_pages_visible_default.rb +0 -11
  146. data/db/migrate/20110228182659_remove_default_page_layout_from_pages.rb +0 -11
  147. data/db/migrate/20110414163140_remove_display_name_from_elements.rb +0 -11
  148. data/db/migrate/20110511100516_rename_essence_texts_title_to_link_title.rb +0 -9
  149. data/db/migrate/20110529130429_create_cells.rb +0 -14
  150. data/db/migrate/20110529130500_add_cell_id_to_elements.rb +0 -11
  151. data/db/migrate/20110530102804_change_pages_page_layout_column.rb +0 -11
  152. data/db/migrate/20110707190728_add_render_size_to_essence_pictures.rb +0 -9
  153. data/db/migrate/20110711142057_change_open_link_in_new_window_to_link_target.rb +0 -19
  154. data/db/migrate/20110919110451_add_default_role_to_users.rb +0 -9
  155. data/db/migrate/20111116125112_namespace_alchemy_models.rb +0 -23
  156. data/db/migrate/20120216135355_add_country_code_to_languages.rb +0 -9
  157. data/db/migrate/20120608085509_create_alchemy_essence_selects.rb +0 -11
  158. data/db/migrate/20120611221734_create_alchemy_essence_booleans.rb +0 -11
  159. data/db/migrate/20120704181529_add_upload_hash_to_alchemy_picture.rb +0 -5
  160. data/db/migrate/20120705214247_acts_as_taggable_on_migration.rb +0 -28
  161. data/db/migrate/20120728185830_add_cached_tag_list_to_alchemy_pictures.rb +0 -5
  162. data/db/migrate/20120831135441_set_alchemy_languages_country_code_default_to_empty_string.rb +0 -9
  163. data/spec/helpers/pictures_helper_spec.rb +0 -14
  164. data/vendor/assets/javascripts/jquery_plugins/jquery.selectBoxIt.js +0 -1909
@@ -95,7 +95,6 @@ div.sitemap_page:hover a.sitemap_pagename_link {
95
95
  }
96
96
 
97
97
  div.sitemap_left_images {
98
- width: 16px;
99
98
  margin-top: 3px;
100
99
  float: left;
101
100
  margin-right: 8px;
@@ -32,7 +32,7 @@ table tr td.tools {
32
32
  @include disable-user-select;
33
33
  }
34
34
 
35
- td.label, td.input, td.submit, td.select, td.value {
35
+ td.label, td.input, td.submit, td.select, td.value, td.note {
36
36
  padding: 2px 0;
37
37
  vertical-align: top;
38
38
  }
@@ -45,6 +45,8 @@ td.input, td.submit, td.select, td.value {
45
45
  }
46
46
  }
47
47
 
48
+ td.submit p.foot_note { float: left; padding-top: 1em }
49
+
48
50
  td.label {
49
51
  white-space: nowrap;
50
52
  width: 80px;
@@ -3,14 +3,14 @@ module Alchemy
3
3
  class BaseController < Alchemy::BaseController
4
4
 
5
5
  include Userstamp
6
-
6
+ before_filter { enforce_ssl if ssl_required? && !request.ssl? }
7
7
  before_filter :set_translation
8
8
 
9
9
  helper_method :clipboard_empty?, :trash_empty?, :get_clipboard, :is_admin?
10
10
 
11
11
  filter_access_to :all
12
12
 
13
- rescue_from Exception, :with => :exception_handler
13
+ rescue_from Exception, :with => :exception_handler unless Rails.env == 'test'
14
14
 
15
15
  layout 'alchemy/admin'
16
16
 
@@ -24,16 +24,13 @@ module Alchemy
24
24
 
25
25
  # Logs the current exception to the error log.
26
26
  def exception_logger(e)
27
- message = "\n+++++++++ Error: #{e} +++++++++++++\n\n"
28
- e.backtrace.each do |line|
29
- message += "#{line}\n"
30
- end
31
- logger.error(message)
27
+ Rails.logger.error("\n#{e.class} #{e.message} in #{e.backtrace.first}")
28
+ Rails.logger.error(e.backtrace[1..50].each { |l| l.gsub(/#{Rails.root.to_s}/, '') }.join("\n"))
32
29
  end
33
30
 
34
31
  # Displays an error notice in the Alchemy backend.
35
32
  def show_error_notice(e)
36
- @notice = "Error: #{e}"
33
+ @notice = "Error: #{e.message[0..99]}"
37
34
  @trace = e.backtrace
38
35
  if request.xhr?
39
36
  render :action => "error_notice", :layout => false
@@ -86,18 +83,28 @@ module Alchemy
86
83
  current_user.admin?
87
84
  end
88
85
 
89
- def render_errors_or_redirect(object, redirect_url, flash_notice, button = nil)
86
+ # Displays errors in a #errors div if any errors are present on the object.
87
+ # Or redirects to the given redirect url.
88
+ def render_errors_or_redirect(object, redirect_url, flash_notice)
90
89
  if object.errors.empty?
91
90
  @redirect_url = redirect_url
92
91
  flash[:notice] = t(flash_notice)
93
92
  render :action => :redirect
94
93
  else
95
- render_remote_errors(object, button)
94
+ render_remote_errors(object)
96
95
  end
97
96
  end
98
97
 
99
- def render_remote_errors(object, button = nil)
100
- @button = button
98
+ # Displays an unordered list of objects errors in an errors div.
99
+ #
100
+ # Note: You have to have a hidden div with the id +#errors+ in your form, to make this work.
101
+ #
102
+ # You can pass a div id as second argument to display the errors in alternative div.
103
+ #
104
+ # Hint: If you use an alternative div, please use the +errors+ css class to get the correct styling.
105
+ #
106
+ def render_remote_errors(object, error_div_id = nil)
107
+ @error_div_id = error_div_id || '#errors'
101
108
  @errors = ("<ul>" + object.errors.full_messages.map { |e| "<li>#{e}</li>" }.join + "</ul>").html_safe
102
109
  render :action => :remote_errors
103
110
  end
@@ -37,30 +37,31 @@ module Alchemy
37
37
  # Creates a element as discribed in config/alchemy/elements.yml on page via AJAX.
38
38
  def create
39
39
  @page = Page.find(params[:element][:page_id])
40
- @element_name = params[:element][:name] # storing the original element name, because the model alters the params hash
41
- @paste_from_clipboard = !params[:paste_from_clipboard].blank?
42
- if @paste_from_clipboard
43
- source_element = Element.find(element_from_clipboard[:id])
44
- @element = Element.copy(source_element, {:page_id => @page.id})
45
- if element_from_clipboard[:action] == 'cut'
46
- @cutted_element_id = source_element.id
47
- @clipboard.remove :elements, source_element.id
48
- source_element.destroy
40
+ Element.transaction do
41
+ if @paste_from_clipboard = params[:paste_from_clipboard].present?
42
+ @element = paste_element_from_clipboard
43
+ else
44
+ @element = Element.new_from_scratch(params[:element])
45
+ if @page.can_have_cells?
46
+ @cell = find_or_create_cell
47
+ @element.cell = @cell
48
+ end
49
+ @element.save!
50
+ end
51
+ if @insert_at_top = @page.definition['insert_elements_at'] == 'top'
52
+ @element.move_to_top
49
53
  end
50
- else
51
- @element = Element.new_from_scratch(params[:element])
52
54
  end
53
- put_element_in_cell if @page.can_have_cells?
54
- if @element.save
55
+ @cell_name = @cell.nil? ? "for_other_elements" : @cell.name
56
+ if @element.valid?
55
57
  render :action => :create
56
58
  else
57
- render_remote_errors(@element, 'form#new_alchemy_element button.button')
59
+ render_remote_errors(@element, params[:paste_from_clipboard].nil? ? nil : '#paste_element_errors')
58
60
  end
59
61
  end
60
62
 
61
- # Saves all contents in the elements by calling save_content on each content
63
+ # Saves all contents in the elements by calling save_contents.
62
64
  # And then updates the element itself.
63
- # If a Ferret::FileNotFoundError raises we gonna catch it and rebuilding the index.
64
65
  def update
65
66
  @element = Element.find_by_id(params[:id])
66
67
  if @element.save_contents(params)
@@ -102,16 +103,26 @@ module Alchemy
102
103
 
103
104
  private
104
105
 
105
- def put_element_in_cell
106
- element_with_cell_name = @paste_from_clipboard ? params[:paste_from_clipboard] : @element_name
107
- cell_definition = Cell.definition_for(element_with_cell_name.split('#').last) if !element_with_cell_name.blank?
108
- if cell_definition
109
- @cell = @page.cells.find_or_create_by_name(cell_definition['name'])
110
- @element.cell = @cell
111
- return true
106
+ # Returns the cell for element name in params.
107
+ # Creates the cell if necessary.
108
+ def find_or_create_cell
109
+ if @paste_from_clipboard
110
+ element_with_cell_name = params[:paste_from_clipboard]
112
111
  else
113
- return false
112
+ element_with_cell_name = params[:element][:name]
113
+ end
114
+ if element_with_cell_name.blank?
115
+ raise "No element with cell name given. Please provide the cell name after the element name (or id) seperated by #."
116
+ end
117
+ unless element_with_cell_name.include?('#')
118
+ return nil
114
119
  end
120
+ cell_name = element_with_cell_name.split('#').last
121
+ cell_definition = Cell.definition_for(cell_name)
122
+ if cell_definition.blank?
123
+ raise "Cell definition not found for #{cell_name}"
124
+ end
125
+ @page.cells.find_or_create_by_name(cell_definition['name'])
115
126
  end
116
127
 
117
128
  def element_from_clipboard
@@ -119,6 +130,23 @@ module Alchemy
119
130
  @clipboard.get(:elements, params[:paste_from_clipboard])
120
131
  end
121
132
 
133
+ def paste_element_from_clipboard
134
+ @source_element = Element.find(element_from_clipboard[:id])
135
+ new_attributes = {:page_id => @page.id}
136
+ if @page.can_have_cells?
137
+ new_attributes = new_attributes.merge({:cell_id => find_or_create_cell.id})
138
+ end
139
+ element = Element.copy(@source_element, new_attributes)
140
+ cut_element if element_from_clipboard[:action] == 'cut'
141
+ element
142
+ end
143
+
144
+ def cut_element
145
+ @cutted_element_id = @source_element.id
146
+ @clipboard.remove :elements, @source_element.id
147
+ @source_element.destroy
148
+ end
149
+
122
150
  end
123
151
  end
124
152
  end
@@ -34,11 +34,14 @@ module Alchemy
34
34
  # Setting the locale to pages language. so the page content has its correct translation
35
35
  ::I18n.locale = @page.language_code
36
36
  render :layout => layout_for_page
37
+ rescue Exception => e
38
+ exception_logger(e)
39
+ render :file => Rails.root.join('public', '500.html'), :status => 500, :layout => false
37
40
  end
38
41
 
39
42
  def new
40
43
  @page = Page.new(:layoutpage => params[:layoutpage] == 'true', :parent_id => params[:parent_id])
41
- @page_layouts = PageLayout.get_layouts_for_select(session[:language_id], @page.layoutpage?)
44
+ @page_layouts = PageLayout.layouts_for_select(session[:language_id], @page.layoutpage?)
42
45
  @clipboard_items = Page.all_from_clipboard_for_select(get_clipboard[:pages], session[:language_id], @page.layoutpage?)
43
46
  render :layout => false
44
47
  end
@@ -49,18 +52,18 @@ module Alchemy
49
52
  params[:page][:language_code] ||= parent.language ? parent.language.code : Language.get_default.code
50
53
  if !params[:paste_from_clipboard].blank?
51
54
  source_page = Page.find(params[:paste_from_clipboard])
52
- page = Page.copy(source_page, {
55
+ @page = Page.copy(source_page, {
53
56
  :name => params[:page][:name].blank? ? source_page.name + ' (' + t('Copy') + ')' : params[:page][:name],
54
57
  :urlname => '',
55
58
  :title => '',
56
59
  :parent_id => params[:page][:parent_id],
57
60
  :language => parent.language
58
61
  })
59
- source_page.copy_children_to(page) unless source_page.children.blank?
62
+ source_page.copy_children_to(@page) unless source_page.children.blank?
60
63
  else
61
- page = Page.create(params[:page])
64
+ @page = Page.create(params[:page])
62
65
  end
63
- render_errors_or_redirect(page, parent.layoutpage? ? admin_layoutpages_path : admin_pages_path, t("Page created", :name => page.name), '#alchemyOverlay button.button')
66
+ render_errors_or_redirect(@page, @page.valid? ? edit_admin_page_path(@page) : admin_pages_path, t("Page created", :name => @page.name))
64
67
  end
65
68
 
66
69
  # Edit the content of the page and all its elements and contents.
@@ -82,12 +85,15 @@ module Alchemy
82
85
  if @page.redirects_to_external?
83
86
  render :action => 'configure_external', :layout => false
84
87
  else
88
+ @page_layouts = PageLayout.layouts_with_own_for_select(@page.page_layout, session[:language_id], @page.layoutpage?)
85
89
  render :layout => false
86
90
  end
87
91
  end
88
92
 
89
93
  def update
90
94
  # fetching page via before filter
95
+ # storing old page_layout value, because unfurtunally rails @page.changes does not work here.
96
+ @old_page_layout = @page.page_layout
91
97
  if @page.update_attributes(params[:page])
92
98
  @notice = t("Page saved", :name => @page.name)
93
99
  @while_page_edit = request.referer.include?('edit')
@@ -63,10 +63,9 @@ module Alchemy
63
63
  @_resource_handler ||= Alchemy::Resource.new(controller_path, alchemy_module)
64
64
  end
65
65
 
66
- protected
66
+ protected
67
67
 
68
-
69
- def render_errors_or_redirect(object, redirect_url, flash_notice, button = nil)
68
+ def render_errors_or_redirect(object, redirect_url, flash_notice)
70
69
  if object.errors.empty?
71
70
  @redirect_url = redirect_url
72
71
  flash[:notice] = t(flash_notice)
@@ -76,7 +75,7 @@ module Alchemy
76
75
  end
77
76
  else
78
77
  respond_to do |format|
79
- format.js { render_remote_errors(object, button) }
78
+ format.js { render_remote_errors(object) }
80
79
  format.html { render :action => :new }
81
80
  end
82
81
  end
@@ -51,6 +51,7 @@ module Alchemy
51
51
 
52
52
  def update
53
53
  # User is fetched via before filter
54
+ params[:user].delete(:role) unless permitted_to?(:update_role)
54
55
  @user.update_attributes(params[:user])
55
56
  Notifications.admin_user_created(@user).deliver if params[:send_credentials]
56
57
  render_errors_or_redirect(
@@ -15,15 +15,19 @@ module Alchemy
15
15
  def current_server
16
16
  # For local development server
17
17
  if request.port != 80
18
- "http://#{request.host}:#{request.port}"
18
+ "#{request.protocol}#{request.host}:#{request.port}"
19
19
  # For remote production server
20
20
  else
21
- "http://#{request.host}"
21
+ "#{request.protocol}#{request.host}"
22
22
  end
23
23
  end
24
24
 
25
+ # Returns the configuratin value of given key.
26
+ #
27
+ # Config file is in +config/alchemy/config.yml+
28
+ #
25
29
  def configuration(name)
26
- return Alchemy::Config.get(name)
30
+ Alchemy::Config.get(name)
27
31
  end
28
32
 
29
33
  def multi_language?
@@ -56,6 +60,8 @@ module Alchemy
56
60
  session[:current_locale] = ::I18n.locale = params[:locale]
57
61
  elsif current_user && current_user.language.present?
58
62
  ::I18n.locale = current_user.language
63
+ elsif Rails.env == 'test' # OMG I hate to do this. But it helps...
64
+ ::I18n.locale = 'en'
59
65
  else
60
66
  ::I18n.locale = request.env['HTTP_ACCEPT_LANGUAGE'].try(:scan, /^[a-z]{2}/).try(:first)
61
67
  end
@@ -66,8 +72,7 @@ module Alchemy
66
72
  if params[:lang].blank? and session[:language_id].blank?
67
73
  set_language_to_default
68
74
  elsif !params[:lang].blank?
69
- set_language_from(params[:lang])
70
- ::I18n.locale = params[:lang]
75
+ ::I18n.locale = set_language_from(params[:lang])
71
76
  end
72
77
  end
73
78
 
@@ -95,9 +100,8 @@ module Alchemy
95
100
 
96
101
  def store_language_in_session(language)
97
102
  if language && language.id
98
- return if language.id == session[:language_id]
99
- session[:language_code] = language.code
100
103
  session[:language_id] = language.id
104
+ session[:language_code] = language.code
101
105
  else
102
106
  logger.warn "!!!! Language not found for #{language.inspect}. Setting to default!"
103
107
  set_language_to_default
@@ -159,6 +163,28 @@ module Alchemy
159
163
  render :file => Rails.root.join("public/404.html"), :status => 404, :layout => !@page.nil?
160
164
  end
161
165
 
166
+ # Enforce ssl for login and all admin modules.
167
+ #
168
+ # Default is +false+
169
+ #
170
+ # === Usage
171
+ #
172
+ # #config.yml
173
+ # require_ssl: true
174
+ #
175
+ # === Note
176
+ #
177
+ # You have to create a ssl certificate if you want to use the ssl protection
178
+ #
179
+ def ssl_required?
180
+ (Rails.env == 'production' || Rails.env == 'staging') && configuration(:require_ssl)
181
+ end
182
+
183
+ # Redirects request to ssl.
184
+ def enforce_ssl
185
+ redirect_to url_for(protocol: 'https')
186
+ end
187
+
162
188
  protected
163
189
 
164
190
  def permission_denied
@@ -171,7 +197,7 @@ module Alchemy
171
197
  elsif request.xhr?
172
198
  respond_to do |format|
173
199
  format.js {
174
- render :js => "Alchemy.growl('#{t('You are not authorized')}', 'warning'); Alchemy.enableButton('button.button, a.button, input.button');"
200
+ render :js => "Alchemy.growl('#{t('You are not authorized')}', 'warning'); Alchemy.Buttons.enable();"
175
201
  }
176
202
  format.html {
177
203
  render :partial => 'alchemy/admin/partials/flash', :locals => {:message => t('You are not authorized'), :flash_type => 'warning'}
@@ -3,7 +3,7 @@ module Alchemy
3
3
 
4
4
  caches_page :show, :thumbnail, :zoom
5
5
 
6
- before_filter :load_picture
6
+ before_filter :load_picture, :ensure_secure_params
7
7
 
8
8
  filter_access_to :show, :attribute_check => true, :model => Alchemy::Picture, :load_method => :load_picture
9
9
  filter_access_to :thumbnail
@@ -60,5 +60,20 @@ module Alchemy
60
60
  @picture ||= Picture.find(params[:id])
61
61
  end
62
62
 
63
+ def ensure_secure_params
64
+ token = params[:sh]
65
+ digest = Digest::SHA1.hexdigest(secured_params)[0..15]
66
+ bad_request unless token && (token == digest)
67
+ end
68
+
69
+ def secured_params
70
+ [params[:id], params[:size], params[:crop], params[:crop_from], params[:crop_size], Rails.configuration.secret_token].join('-')
71
+ end
72
+
73
+ def bad_request
74
+ render :text => "Bad picture parameters in #{request.path}", :status => 400
75
+ return false
76
+ end
77
+
63
78
  end
64
79
  end
@@ -1,6 +1,7 @@
1
1
  module Alchemy
2
2
  class UserSessionsController < Alchemy::BaseController
3
3
 
4
+ before_filter { enforce_ssl if ssl_required? && !request.ssl? }
4
5
  before_filter :set_translation
5
6
  before_filter :check_user_count, :only => :login
6
7
 
@@ -20,9 +21,13 @@ module Alchemy
20
21
  if params[:send_credentials]
21
22
  Notifications.admin_user_created(@user).deliver
22
23
  end
24
+ flash[:notice] = t('Successfully signup admin user')
23
25
  redirect_to admin_dashboard_path
24
26
  end
25
27
  end
28
+ rescue Errno::ECONNREFUSED => e
29
+ flash[:error] = t(:signup_mail_delivery_error)
30
+ redirect_to admin_dashboard_path
26
31
  end
27
32
 
28
33
  def login
@@ -63,7 +68,7 @@ module Alchemy
63
68
  redirect_to root_url
64
69
  end
65
70
 
66
- private
71
+ private
67
72
 
68
73
  def check_user_count
69
74
  if User.count == 0
@@ -45,6 +45,20 @@ module Alchemy
45
45
  content_tag('span', '', :class => "icon #{icon_class}")
46
46
  end
47
47
 
48
+ # Returns a div with an icon and the passed content
49
+ # The default message type is info, but you can also pass
50
+ # other types like :warning or :error
51
+ #
52
+ # === Usage:
53
+ #
54
+ # <%= render_message :warning do
55
+ # <p>Caution! This is a warning!</p>
56
+ # <% end %>
57
+ #
58
+ def render_message(type = :info, &blk)
59
+ content_tag :div, render_icon(type) + capture(&blk), :class => "#{type} message"
60
+ end
61
+
48
62
  # Returns an array of all pages in the same branch from current.
49
63
  # I.e. used to find the active page in navigation.
50
64
  def breadcrumb(current)