alchemy_cms 2.5.0.b9 → 2.5.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/alchemy_cms.gemspec +2 -1
  2. data/app/assets/javascripts/alchemy/alchemy.base.js +0 -27
  3. data/app/assets/javascripts/alchemy/alchemy.growler.js +1 -1
  4. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +0 -1
  5. data/app/assets/javascripts/alchemy/alchemy.onload.js.coffee +0 -4
  6. data/app/assets/javascripts/alchemy/alchemy.page_sorter.js +0 -1
  7. data/app/assets/stylesheets/alchemy/admin.css.scss +1 -0
  8. data/app/assets/stylesheets/alchemy/archive.scss +8 -6
  9. data/app/assets/stylesheets/alchemy/base.scss +3 -92
  10. data/app/assets/stylesheets/alchemy/elements.scss +2 -2
  11. data/app/assets/stylesheets/alchemy/flash.scss +16 -12
  12. data/app/assets/stylesheets/alchemy/frame.scss +10 -5
  13. data/app/assets/stylesheets/alchemy/icons.scss +2 -2
  14. data/app/assets/stylesheets/alchemy/pagination.scss +5 -5
  15. data/app/assets/stylesheets/alchemy/tables.scss +2 -2
  16. data/app/assets/stylesheets/alchemy/toolbar.scss +79 -0
  17. data/app/controllers/alchemy/admin/base_controller.rb +3 -2
  18. data/app/controllers/alchemy/admin/dashboard_controller.rb +1 -1
  19. data/app/controllers/alchemy/admin/pictures_controller.rb +1 -1
  20. data/app/controllers/alchemy/admin/users_controller.rb +8 -2
  21. data/app/controllers/alchemy/attachments_controller.rb +1 -1
  22. data/app/controllers/alchemy/base_controller.rb +8 -0
  23. data/app/controllers/alchemy/pages_controller.rb +4 -0
  24. data/app/controllers/alchemy/passwords_controller.rb +23 -0
  25. data/app/controllers/alchemy/user_sessions_controller.rb +20 -49
  26. data/app/controllers/alchemy/users_controller.rb +49 -0
  27. data/app/mailers/alchemy/notifications.rb +5 -0
  28. data/app/models/alchemy/content.rb +6 -2
  29. data/app/models/alchemy/element.rb +9 -5
  30. data/app/models/alchemy/essence_richtext.rb +28 -16
  31. data/app/models/alchemy/essence_text.rb +22 -13
  32. data/app/models/alchemy/message.rb +1 -1
  33. data/app/models/alchemy/page.rb +7 -2
  34. data/app/models/alchemy/user.rb +66 -24
  35. data/app/views/alchemy/admin/dashboard/index.html.erb +1 -1
  36. data/app/views/alchemy/admin/essence_files/edit.html.erb +1 -0
  37. data/app/views/alchemy/admin/pages/_create_language_form.html.erb +8 -1
  38. data/app/views/alchemy/admin/partials/_flash.html.erb +1 -1
  39. data/app/views/alchemy/admin/users/_table.html.erb +2 -2
  40. data/app/views/alchemy/admin/users/_user.html.erb +1 -1
  41. data/app/views/alchemy/admin/users/index.html.erb +1 -1
  42. data/app/views/alchemy/notifications/admin_user_created.de.text.erb +11 -0
  43. data/app/views/alchemy/notifications/admin_user_created.en.text.erb +11 -0
  44. data/app/views/alchemy/notifications/registered_user_created.text.erb +2 -1
  45. data/app/views/alchemy/notifications/reset_password_instructions.de.text.erb +8 -0
  46. data/app/views/alchemy/notifications/reset_password_instructions.en.text.erb +8 -0
  47. data/app/views/alchemy/passwords/edit.html.erb +35 -0
  48. data/app/views/alchemy/passwords/new.html.erb +30 -0
  49. data/app/views/alchemy/user_sessions/leave.html.erb +3 -3
  50. data/app/views/alchemy/user_sessions/{login.html.erb → new.html.erb} +5 -2
  51. data/app/views/alchemy/{user_sessions/signup.html.erb → users/new.html.erb} +0 -0
  52. data/config/alchemy/config.yml +12 -0
  53. data/config/initializers/devise.rb +242 -0
  54. data/config/locales/alchemy.de.yml +12 -39
  55. data/config/locales/alchemy.en.yml +4 -31
  56. data/config/locales/devise.de.yml +57 -0
  57. data/config/locales/devise.en.yml +60 -0
  58. data/config/routes.rb +37 -21
  59. data/db/migrate/20130121092645_migrate_to_devise.rb +24 -0
  60. data/lib/alchemy/authentication_helpers.rb +0 -13
  61. data/lib/alchemy/engine.rb +2 -2
  62. data/lib/alchemy/essence.rb +2 -2
  63. data/lib/alchemy/upgrader.rb +33 -0
  64. data/lib/alchemy/version.rb +1 -1
  65. data/lib/alchemy_cms.rb +2 -1
  66. data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +1 -1
  67. data/lib/rails/generators/alchemy/devise/devise_generator.rb +24 -0
  68. data/lib/rails/generators/alchemy/scaffold/files/elements.yml +1 -111
  69. data/lib/rails/generators/alchemy/scaffold/templates/page_layouts.yml.tt +1 -27
  70. data/lib/tasks/ferret.rake +6 -6
  71. data/spec/controllers/admin/clipboard_controller_spec.rb +2 -3
  72. data/spec/controllers/admin/contents_controller_spec.rb +1 -2
  73. data/spec/controllers/admin/elements_controller_spec.rb +1 -2
  74. data/spec/controllers/admin/languages_controller_spec.rb +2 -3
  75. data/spec/controllers/admin/pages_controller_spec.rb +2 -3
  76. data/spec/controllers/admin/trash_controller_spec.rb +1 -2
  77. data/spec/controllers/admin/users_controller_spec.rb +36 -5
  78. data/spec/controllers/attachments_controller_spec.rb +2 -4
  79. data/spec/controllers/base_controller_spec.rb +25 -0
  80. data/spec/controllers/elements_controller_spec.rb +1 -2
  81. data/spec/controllers/passwords_controller_spec.rb +16 -0
  82. data/spec/controllers/pictures_controller_spec.rb +1 -2
  83. data/spec/controllers/user_sessions_controller_spec.rb +21 -0
  84. data/spec/controllers/users_controller_spec.rb +67 -0
  85. data/spec/dummy/db/migrate/20130121092645_migrate_to_devise.rb +24 -0
  86. data/spec/dummy/db/schema.rb +17 -16
  87. data/spec/factories.rb +2 -0
  88. data/spec/integration/pages_controller_spec.rb +9 -1
  89. data/spec/models/content_spec.rb +11 -0
  90. data/spec/models/element_spec.rb +11 -2
  91. data/spec/models/essence_richtext_spec.rb +42 -6
  92. data/spec/models/essence_text_spec.rb +41 -0
  93. data/spec/models/page_spec.rb +39 -0
  94. data/spec/models/user_spec.rb +95 -6
  95. data/spec/spec_helper.rb +2 -3
  96. data/spec/support/alchemy/controller_hacks.rb +1 -1
  97. data/spec/support/alchemy/specs_helpers.rb +4 -4
  98. metadata +47 -10
  99. data/app/models/alchemy/user_session.rb +0 -14
  100. data/app/views/alchemy/notifications/admin_user_created.text.erb +0 -13
  101. data/app/views/alchemy/user_sessions/logout.html.erb +0 -3
@@ -30,7 +30,8 @@ module Alchemy
30
30
 
31
31
  # Displays an error notice in the Alchemy backend.
32
32
  def show_error_notice(e)
33
- @notice = "Error: #{e.message[0..99]}"
33
+ # truncate the message, because very long error messages (i.e from mysql2) causes cookie oveflow errors
34
+ @notice = "Error: #{e.message[0..255]}"
34
35
  @trace = e.backtrace
35
36
  if request.xhr?
36
37
  render :action => "error_notice", :layout => false
@@ -127,7 +128,7 @@ module Alchemy
127
128
  def per_page_value_for_screen_size
128
129
  return 25 if session[:screen_size].blank?
129
130
  screen_height = session[:screen_size].split('x').last.to_i
130
- (screen_height / 30) - 12
131
+ (screen_height / 30) - 10
131
132
  end
132
133
 
133
134
  end
@@ -8,7 +8,7 @@ module Alchemy
8
8
  @last_edited_pages = Page.all_last_edited_from(current_user)
9
9
  @locked_pages = Page.all_locked
10
10
  @online_users = User.logged_in.to_a - [current_user]
11
- @first_time = current_user.login_count == 1 && current_user.last_login_at.nil?
11
+ @first_time = current_user.sign_in_count == 1 && current_user.last_sign_in_at.nil?
12
12
  end
13
13
 
14
14
  end
@@ -157,7 +157,7 @@ module Alchemy
157
157
  when 'large'
158
158
  per_page = in_overlay? ? 4 : (per_page_value_for_screen_size / 1.7).floor + 1
159
159
  else
160
- per_page = in_overlay? ? 9 : (per_page_value_for_screen_size / 1.0).ceil + 1
160
+ per_page = in_overlay? ? 9 : (per_page_value_for_screen_size / 1.0).ceil + 4
161
161
  end
162
162
  return per_page
163
163
  end
@@ -50,8 +50,14 @@ module Alchemy
50
50
  def update
51
51
  # User is fetched via before filter
52
52
  params[:user].delete(:role) unless permitted_to?(:update_role)
53
- @user.update_attributes(params[:user])
54
- Notifications.admin_user_created(@user).deliver if params[:send_credentials]
53
+ if params[:user][:password].present?
54
+ @user.update_attributes(params[:user])
55
+ else
56
+ @user.update_without_password(params[:user])
57
+ end
58
+ if params[:send_credentials]
59
+ Notifications.admin_user_created(@user).deliver
60
+ end
55
61
  render_errors_or_redirect(
56
62
  @user,
57
63
  admin_users_path,
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- class AttachmentsController < Alchemy::BaseController
2
+ class AttachmentsController < BaseController
3
3
 
4
4
  filter_access_to [:show, :download], :attribute_check => true, :model => Alchemy::Attachment, :load_method => :load_attachment
5
5
 
@@ -9,6 +9,7 @@ module Alchemy
9
9
  before_filter :set_current_site
10
10
  before_filter :set_language
11
11
  before_filter :mailer_set_url_options
12
+ before_filter :store_user_request_time
12
13
 
13
14
  helper_method :current_server, :current_site
14
15
 
@@ -187,6 +188,13 @@ module Alchemy
187
188
  redirect_to url_for(protocol: 'https')
188
189
  end
189
190
 
191
+ # Stores the users request time.
192
+ def store_user_request_time
193
+ if user_signed_in?
194
+ current_user.store_request_time!
195
+ end
196
+ end
197
+
190
198
  protected
191
199
 
192
200
  def permission_denied
@@ -76,6 +76,10 @@ module Alchemy
76
76
  # currently active language.
77
77
  Page.language_root_for(@language.id)
78
78
  end
79
+ rescue ArgumentError => e
80
+ # If encoding errors raises (ie. because of invalid byte chars in params),
81
+ # we render a 404 page
82
+ raise ActionController::RoutingError.new(e.message)
79
83
  end
80
84
 
81
85
  def enforce_primary_host_for_site
@@ -0,0 +1,23 @@
1
+ module Alchemy
2
+ class PasswordsController < Devise::PasswordsController
3
+
4
+ before_filter { enforce_ssl if ssl_required? && !request.ssl? }
5
+ before_filter :set_translation
6
+
7
+ layout 'alchemy/admin'
8
+
9
+ helper 'Alchemy::Admin::Base'
10
+
11
+ private
12
+
13
+ # Override for Devise method
14
+ def new_session_path(resource_name)
15
+ alchemy.login_path
16
+ end
17
+
18
+ def edit_password_url(resource, options={})
19
+ alchemy.edit_password_url(options)
20
+ end
21
+
22
+ end
23
+ end
@@ -1,56 +1,31 @@
1
1
  module Alchemy
2
- class UserSessionsController < Alchemy::BaseController
2
+ class UserSessionsController < Devise::SessionsController
3
3
 
4
4
  before_filter { enforce_ssl if ssl_required? && !request.ssl? }
5
5
  before_filter :set_translation
6
- before_filter :check_user_count, :only => :login
6
+ before_filter :check_user_count, :only => :new
7
7
 
8
8
  layout 'alchemy/admin'
9
9
 
10
10
  helper 'Alchemy::Admin::Base'
11
11
 
12
- # Signup only works if no user is present in database.
13
- def signup
14
- @user_genders = User.genders_for_select
15
- if request.get?
16
- redirect_to admin_dashboard_path if User.count != 0
17
- @user = User.new({:role => 'admin'})
18
- else
19
- @user = User.new(params[:user])
20
- if @user.save
21
- if params[:send_credentials]
22
- Notifications.admin_user_created(@user).deliver
23
- end
24
- flash[:notice] = _t('Successfully signup admin user')
25
- redirect_to admin_dashboard_path
26
- end
27
- end
28
- rescue Errno::ECONNREFUSED => e
29
- flash[:error] = _t(:signup_mail_delivery_error)
30
- redirect_to admin_dashboard_path
12
+ def new
13
+ super
31
14
  end
32
15
 
33
- def login
34
- if current_user
35
- redirect_to admin_dashboard_path, :notice => _t('You are already logged in')
36
- else
37
- if request.get?
38
- @user_session = UserSession.new()
39
- flash.now[:info] = params[:message] || _t("welcome_please_identify_notice")
16
+ def create
17
+ authenticate_user!
18
+ if user_signed_in?
19
+ store_screen_size
20
+ if session[:redirect_path].blank?
21
+ redirect_path = admin_dashboard_path
40
22
  else
41
- @user_session = UserSession.new(params[:alchemy_user_session])
42
- store_screen_size
43
- if @user_session.save
44
- if session[:redirect_path].blank?
45
- redirect_to admin_dashboard_path
46
- else
47
- # We have to strip double slashes from beginning of path, because of strange rails/rack bug.
48
- redirect_to session[:redirect_path].gsub(/^\/{2,}/, '/')
49
- end
50
- else
51
- render
52
- end
23
+ # We have to strip double slashes from beginning of path, because of strange rails/rack bug.
24
+ redirect_path = session[:redirect_path].gsub(/^\/{2,}/, '/')
53
25
  end
26
+ redirect_to redirect_path, :notice => t(:signed_in, :scope => 'devise.sessions')
27
+ else
28
+ super
54
29
  end
55
30
  end
56
31
 
@@ -58,21 +33,17 @@ module Alchemy
58
33
  render :layout => false
59
34
  end
60
35
 
61
- def logout
62
- message = params[:message] || _t("logged_out")
63
- @user_session = UserSession.find
64
- if @user_session
65
- @user_session.destroy
66
- end
67
- flash[:info] = message
68
- redirect_to root_url
36
+ def destroy
37
+ cookies.clear
38
+ session.clear
39
+ super
69
40
  end
70
41
 
71
42
  private
72
43
 
73
44
  def check_user_count
74
45
  if User.count == 0
75
- redirect_to :action => 'signup'
46
+ redirect_to signup_path
76
47
  else
77
48
  return true
78
49
  end
@@ -0,0 +1,49 @@
1
+ module Alchemy
2
+ class UsersController < BaseController
3
+
4
+ before_filter { enforce_ssl if ssl_required? && !request.ssl? }
5
+ before_filter :set_translation
6
+ before_filter :check_user_count
7
+ before_filter :load_genders
8
+
9
+ layout 'alchemy/admin'
10
+
11
+ helper 'Alchemy::Admin::Base'
12
+
13
+ def new
14
+ @signup = true
15
+ @user = User.new(:role => 'admin')
16
+ end
17
+
18
+ def create
19
+ @user = User.new(params[:user])
20
+ if @user.save
21
+ if params[:send_credentials]
22
+ Notifications.admin_user_created(@user).deliver
23
+ end
24
+ flash[:notice] = _t('Successfully signup admin user')
25
+ sign_in :user, @user
26
+ redirect_to admin_dashboard_path
27
+ else
28
+ @signup = true
29
+ render :new
30
+ end
31
+ rescue Errno::ECONNREFUSED => e
32
+ flash[:error] = _t(:signup_mail_delivery_error)
33
+ redirect_to admin_dashboard_path
34
+ end
35
+
36
+ private
37
+
38
+ def load_genders
39
+ @user_genders = User.genders_for_select
40
+ end
41
+
42
+ def check_user_count
43
+ if User.count > 0
44
+ redirect_to admin_dashboard_path
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -21,5 +21,10 @@ module Alchemy
21
21
  )
22
22
  end
23
23
 
24
+ def reset_password_instructions(user, opts={})
25
+ @user = user
26
+ mail :to => user.email, :subject => Alchemy::I18n.t("Reset password instructions")
27
+ end
28
+
24
29
  end
25
30
  end
@@ -166,8 +166,12 @@ module Alchemy
166
166
  essence.ingredient = value
167
167
  end
168
168
 
169
- # Calls essence.update_attributes. Called from +Alchemy::Element#save_contents+
170
- # Ads errors to self.base if essence validation fails.
169
+ # Calls essence.update_attributes.
170
+ #
171
+ # Called from +Alchemy::Element#save_contents+
172
+ #
173
+ # Adds errors to self.base if essence validation fails.
174
+ #
171
175
  def update_essence(params={})
172
176
  raise EssenceMissingError if essence.nil?
173
177
  if essence.update_attributes(params)
@@ -44,6 +44,10 @@ module Alchemy
44
44
  scope :excluded, lambda { |names| where(arel_table[:name].not_in(names)) }
45
45
  scope :not_in_cell, where(:cell_id => nil)
46
46
  scope :in_cell, where("#{self.table_name}.cell_id IS NOT NULL")
47
+ # Scope for only the elements from Alchemy::Site.current
48
+ scope :from_current_site, lambda { where(:alchemy_languages => {site_id: Site.current}).joins(:page => :language) }
49
+ # TODO: add this as default_scope
50
+ #default_scope { from_current_site }
47
51
 
48
52
  # class methods
49
53
  class << self
@@ -77,7 +81,7 @@ module Alchemy
77
81
  #
78
82
  def descriptions
79
83
  if ::File.exists? "#{::Rails.root}/config/alchemy/elements.yml"
80
- ::YAML.load_file("#{::Rails.root}/config/alchemy/elements.yml")
84
+ ::YAML.load_file("#{::Rails.root}/config/alchemy/elements.yml") || []
81
85
  else
82
86
  raise LoadError, "Could not find elements.yml file! Please run: rails generate alchemy:scaffold"
83
87
  end
@@ -198,16 +202,16 @@ module Alchemy
198
202
  # Pass an element name to get next of this kind.
199
203
  def next(name = nil)
200
204
  elements = page.elements.published.where(Element.arel_table[:position].gt(position))
201
- elements = elements.where(:name => name) if name.present?
202
- elements.order("position ASC").limit(1).first
205
+ elements = elements.named(name) if name.present?
206
+ elements.reorder("position ASC").limit(1).first
203
207
  end
204
208
 
205
209
  # Returns previous public element from same page.
206
210
  # Pass an element name to get previous of this kind.
207
211
  def prev(name = nil)
208
212
  elements = page.elements.published.where(Element.arel_table[:position].lt(position))
209
- elements = elements.where(:name => name) if name.present?
210
- elements.order("position DESC").limit(1).first
213
+ elements = elements.named(name) if name.present?
214
+ elements.reorder("position DESC").limit(1).first
211
215
  end
212
216
 
213
217
  # Stores the page into `to_be_sweeped_pages` (Pages that have to be sweeped after updating element).
@@ -7,20 +7,38 @@ module Alchemy
7
7
 
8
8
  attr_accessible :do_not_index, :body, :public, :stripped_body
9
9
 
10
- # Require acts_as_ferret only if Ferret full text search is enabled (default).
10
+ before_save :strip_content
11
+
12
+
13
+ # Enable Ferret indexing.
14
+ #
15
+ # But only, if Ferret full text search is enabled (default).
16
+ #
11
17
  # You can disable it in +config/alchemy/config.yml+
18
+ #
12
19
  if Config.get(:ferret) == true
13
20
  require 'acts_as_ferret'
14
- acts_as_ferret(
15
- :fields => {
16
- :stripped_body => {:store => :yes}
17
- },
18
- :remote => false
19
- )
20
- before_save :check_ferret_indexing
21
- end
21
+ acts_as_ferret(:fields => { :stripped_body => {:store => :yes} }, :remote => false)
22
22
 
23
- before_save :strip_content
23
+ # Ensures that the current setting for do_not_index gets updated in the db.
24
+ before_save { write_attribute(:do_not_index, description['do_not_index'] || false); return true }
25
+
26
+ # Disables the ferret indexing, if do_not_index attribute is set to true
27
+ #
28
+ # You can disable indexing in the elements.yml file.
29
+ #
30
+ # === Example
31
+ #
32
+ # name: secrets
33
+ # contents:
34
+ # - name: confidential
35
+ # type: EssenceRichtext
36
+ # do_not_index: true
37
+ #
38
+ def ferret_enabled?(is_bulk_index = false)
39
+ !do_not_index?
40
+ end
41
+ end
24
42
 
25
43
  private
26
44
 
@@ -28,12 +46,6 @@ module Alchemy
28
46
  self.stripped_body = strip_tags(self.body)
29
47
  end
30
48
 
31
- def check_ferret_indexing
32
- if self.do_not_index
33
- self.disable_ferret(:always)
34
- end
35
- end
36
-
37
49
  # Stripping HTML Tags and only returns plain text.
38
50
  def strip_tags(html)
39
51
  return html if html.blank?
@@ -13,24 +13,33 @@ module Alchemy
13
13
  :link_target
14
14
  )
15
15
 
16
- # Require acts_as_ferret only if Ferret full text search is enabled (default).
16
+ # Enable Ferret indexing.
17
+ #
18
+ # But only, if Ferret full text search is enabled (default).
19
+ #
17
20
  # You can disable it in +config/alchemy/config.yml+
21
+ #
18
22
  if Config.get(:ferret) == true
19
23
  require 'acts_as_ferret'
20
- acts_as_ferret(
21
- :fields => {
22
- :body => {:store => :yes}
23
- },
24
- :remote => false
25
- )
26
- before_save :check_ferret_indexing
27
- end
24
+ acts_as_ferret(:fields => { :body => {:store => :yes} }, :remote => false)
28
25
 
29
- private
26
+ # Ensures that the current setting for do_not_index gets updated in the db.
27
+ before_save { write_attribute(:do_not_index, description['do_not_index'] || false); return true }
30
28
 
31
- def check_ferret_indexing
32
- if self.do_not_index
33
- self.disable_ferret(:always)
29
+ # Disables the ferret indexing, if do_not_index attribute is set to true
30
+ #
31
+ # You can disable indexing in the elements.yml file.
32
+ #
33
+ # === Example
34
+ #
35
+ # name: contact_form
36
+ # contents:
37
+ # - name: email
38
+ # type: EssenceText
39
+ # do_not_index: true
40
+ #
41
+ def ferret_enabled?(is_bulk_index = false)
42
+ !do_not_index?
34
43
  end
35
44
  end
36
45