trusty-cms 7.0.2 → 7.0.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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/Gemfile +2 -2
  4. data/Gemfile.lock +89 -102
  5. data/INSTALL.md +8 -6
  6. data/README.md +123 -15
  7. data/app/assets/javascripts/admin/validations/scheduled_status_validation.js +60 -0
  8. data/app/assets/stylesheets/admin/main.scss +2 -1
  9. data/app/assets/stylesheets/admin/partials/_datetime_input.scss +5 -0
  10. data/app/assets/stylesheets/admin/partials/_forms.scss +13 -0
  11. data/app/assets/stylesheets/admin/partials/_messages.scss +4 -0
  12. data/app/controllers/admin/configuration_controller.rb +1 -1
  13. data/app/controllers/admin/extensions_controller.rb +1 -0
  14. data/app/controllers/admin/layouts_controller.rb +2 -1
  15. data/app/controllers/admin/resource_controller.rb +10 -1
  16. data/app/controllers/admin/sites_controller.rb +1 -0
  17. data/app/controllers/admin/snippets_controller.rb +2 -1
  18. data/app/controllers/admin/users_controller.rb +2 -1
  19. data/app/controllers/page_status_controller.rb +61 -0
  20. data/app/controllers/site_controller.rb +0 -15
  21. data/app/helpers/admin/pages_helper.rb +0 -5
  22. data/app/helpers/admin/users_helper.rb +2 -1
  23. data/app/helpers/application_helper.rb +2 -1
  24. data/app/models/admins_site.rb +6 -0
  25. data/app/models/page.rb +3 -10
  26. data/app/models/site.rb +2 -0
  27. data/app/models/status.rb +1 -5
  28. data/app/models/trusty_cms/config.rb +2 -1
  29. data/app/models/user.rb +15 -4
  30. data/app/views/admin/layouts/_choose_site.html.haml +5 -3
  31. data/app/views/admin/layouts/_site_chooser.html.haml +2 -2
  32. data/app/views/admin/pages/_fields.html.haml +15 -6
  33. data/app/views/admin/pages/_node.html.haml +1 -1
  34. data/app/views/admin/snippets/_choose_site.html.haml +2 -1
  35. data/app/views/admin/users/_choose_site.html.haml +2 -1
  36. data/app/views/admin/users/_form.html.haml +3 -1
  37. data/bin/rails +2 -2
  38. data/config/application.rb +1 -0
  39. data/config/initializers/devise.rb +1 -1
  40. data/config/locales/en.yml +11 -9
  41. data/config/routes.rb +1 -0
  42. data/db/migrate/20241108172942_create_site_users.rb +8 -0
  43. data/lib/login_system.rb +15 -15
  44. data/lib/trusty_cms/version.rb +1 -1
  45. data/spec/dummy/config/application.rb +2 -0
  46. data/spec/dummy/db/schema.rb +8 -1
  47. data/spec/factories/snippet.rb +10 -0
  48. data/spec/factories/user.rb +11 -11
  49. data/spec/models/snippets_spec.rb +29 -0
  50. data/spec/models/user_spec.rb +46 -0
  51. data/trusty_cms.gemspec +1 -1
  52. data/vendor/extensions/multi-site-extension/lib/multi_site/scoped_model.rb +17 -11
  53. data/vendor/extensions/multi-site-extension/lib/multi_site/site_chooser_helper.rb +10 -10
  54. metadata +16 -6
  55. data/app/users/_choose_site.html.haml +0 -4
  56. /data/app/assets/stylesheets/admin/partials/{_dateinput.scss → _date_input.scss} +0 -0
@@ -0,0 +1,60 @@
1
+ $(document).ready(function() {
2
+ function isValidDateTime(value) {
3
+ return !isNaN(new Date(value).getTime());
4
+ }
5
+
6
+ function showError(message) {
7
+ $('#published-at-error').text(message);
8
+ $('.error').removeClass('hidden');
9
+ }
10
+
11
+ function hideError() {
12
+ $('.error').addClass('hidden');
13
+ }
14
+
15
+ function validateScheduledStatus(publishedTime, currentTime) {
16
+ if (!isValidDateTime(publishedTime)) {
17
+ showError('Select a valid Date & Time.');
18
+ return false;
19
+ }
20
+ if (publishedTime < currentTime) {
21
+ showError('Scheduled Date & Time cannot be in the past.');
22
+ return false;
23
+ }
24
+
25
+ hideError();
26
+ return true;
27
+ }
28
+
29
+ function validatePublishedStatus(publishedTime, currentTime) {
30
+ if (publishedTime > currentTime) {
31
+ showError('Published Date & Time cannot be in the future. Clear the date and time to publish now, or set the status to Scheduled.');
32
+ return false;
33
+ }
34
+
35
+ hideError();
36
+ return true;
37
+ }
38
+
39
+ function validateDateTime() {
40
+ const publishedAt = $('#page_published_at').val();
41
+ const status = $('#page_status_id').val();
42
+ const publishedTime = new Date(publishedAt);
43
+ const currentTime = new Date();
44
+
45
+ if (status === '90') {
46
+ return validateScheduledStatus(publishedTime, currentTime);
47
+ }
48
+
49
+ if (status === '100') {
50
+ return validatePublishedStatus(publishedTime, currentTime);
51
+ }
52
+ }
53
+
54
+ $('#save-button, #save-and-continue-button').on('click', function(event) {
55
+ if (!validateDateTime()) {
56
+ event.preventDefault();
57
+ event.stopImmediatePropagation();
58
+ }
59
+ });
60
+ });
@@ -20,7 +20,8 @@
20
20
  @import "partials/footer";
21
21
  @import "partials/popup";
22
22
  @import "partials/tabcontrol";
23
- @import "partials/dateinput";
23
+ @import "partials/date_input";
24
+ @import "partials/datetime_input";
24
25
  @import "partials/toolbar";
25
26
  @import "partials/validations";
26
27
  @import "partials/preferences";
@@ -0,0 +1,5 @@
1
+ .datetime {
2
+ border: 1px solid #919191;
3
+ margin: 0.5em;
4
+ padding: 0.5em 1em;
5
+ }
@@ -60,6 +60,19 @@ select {
60
60
  transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
61
61
  }
62
62
 
63
+ select[multiple] {
64
+ height: auto;
65
+
66
+ option {
67
+ padding: 0.5em;
68
+
69
+ &:checked {
70
+ background-color: #e5e6e7;
71
+ font-weight: 700;
72
+ }
73
+ }
74
+ }
75
+
63
76
  label {
64
77
  display: block;
65
78
  }
@@ -10,6 +10,10 @@
10
10
  .error {
11
11
  background-color: #f3c2c2;
12
12
  color: $alt-link-color;
13
+
14
+ &.hidden {
15
+ display: none;
16
+ }
13
17
  }
14
18
 
15
19
  .warning {
@@ -5,7 +5,7 @@ class Admin::ConfigurationController < ApplicationController
5
5
  # and the show and edit views determine what set of config values is shown and made editable.
6
6
 
7
7
  before_action :initialize_config
8
-
8
+ before_action :authorize_role
9
9
  only_allow_access_to :edit, :update,
10
10
  when: [:admin],
11
11
  denied_url: { controller: 'admin/configuration', action: 'show' },
@@ -1,4 +1,5 @@
1
1
  class Admin::ExtensionsController < ApplicationController
2
+ before_action :authorize_role
2
3
  only_allow_access_to :index,
3
4
  when: :admin,
4
5
  denied_url: { controller: 'pages', action: 'index' },
@@ -1,7 +1,8 @@
1
1
  class Admin::LayoutsController < Admin::ResourceController
2
2
  paginate_models
3
+ before_action :authorize_role
3
4
  only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
4
5
  when: %i[designer admin],
5
6
  denied_url: { controller: 'admin/pages', action: 'index' },
6
- denied_message: 'You must have designer privileges to perform this action.'
7
+ denied_message: 'You must have at least editor privileges to perform this action.'
7
8
  end
@@ -1,4 +1,5 @@
1
1
  require 'trusty_cms/resource_responses'
2
+
2
3
  class Admin::ResourceController < ApplicationController
3
4
  extend TrustyCms::ResourceResponses
4
5
 
@@ -95,6 +96,7 @@ class Admin::ResourceController < ApplicationController
95
96
  def will_paginate_options
96
97
  self.class.will_paginate_options || {}
97
98
  end
99
+
98
100
  helper_method :will_paginate_options
99
101
 
100
102
  # a convenience method that returns true if paginate_models has been called on this controller class
@@ -102,6 +104,7 @@ class Admin::ResourceController < ApplicationController
102
104
  def paginated?
103
105
  self.class.paginated == true && params[:pp] != 'all'
104
106
  end
107
+
105
108
  helper_method :paginated?
106
109
 
107
110
  # return a hash of page and per_page that can be used to build a will_paginate collection
@@ -145,7 +148,9 @@ class Admin::ResourceController < ApplicationController
145
148
  def model
146
149
  instance_variable_get("@#{model_symbol}") || load_model
147
150
  end
151
+
148
152
  alias :current_object :model
153
+
149
154
  def model=(object)
150
155
  instance_variable_set("@#{model_symbol}", object)
151
156
  end
@@ -155,13 +160,15 @@ class Admin::ResourceController < ApplicationController
155
160
  model_class.find(params[:id])
156
161
  else
157
162
  model_class.new
158
- end
163
+ end
159
164
  end
160
165
 
161
166
  def models
162
167
  instance_variable_get("@#{plural_model_symbol}") || load_models
163
168
  end
169
+
164
170
  alias :current_objects :models
171
+
165
172
  def models=(objects)
166
173
  instance_variable_set("@#{plural_model_symbol}", objects)
167
174
  end
@@ -177,6 +184,7 @@ class Admin::ResourceController < ApplicationController
177
184
  def plural_model_name
178
185
  model_name.pluralize
179
186
  end
187
+
180
188
  alias :models_name :plural_model_name
181
189
 
182
190
  def model_symbol
@@ -186,6 +194,7 @@ class Admin::ResourceController < ApplicationController
186
194
  def plural_model_symbol
187
195
  model_name.pluralize.underscore.intern
188
196
  end
197
+
189
198
  alias :models_symbol :plural_model_symbol
190
199
 
191
200
  def humanized_model_name
@@ -1,5 +1,6 @@
1
1
  class Admin::SitesController < Admin::ResourceController
2
2
  helper :sites
3
+ before_action :authorize_role
3
4
  only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
4
5
  when: :admin,
5
6
  denied_url: { controller: 'pages', action: 'index' },
@@ -1,7 +1,8 @@
1
1
  class Admin::SnippetsController < Admin::ResourceController
2
2
  paginate_models
3
+ before_action :authorize_role
3
4
  only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
4
5
  when: %i[designer admin],
5
6
  denied_url: { controller: 'admin/pages', action: 'index' },
6
- denied_message: 'You must have designer privileges to perform this action.'
7
+ denied_message: 'You must have at least editor privileges to perform this action.'
7
8
  end
@@ -1,5 +1,6 @@
1
1
  class Admin::UsersController < Admin::ResourceController
2
2
  paginate_models
3
+ before_action :authorize_role
3
4
  only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy,
4
5
  when: :admin,
5
6
  denied_url: { controller: 'pages', action: 'index' },
@@ -48,7 +49,7 @@ class Admin::UsersController < Admin::ResourceController
48
49
 
49
50
  def user_params
50
51
  params.require(:user).permit(:first_name, :last_name, :admin, :designer,
51
- :password, :password_confirmation, :email, :site_id, :notes)
52
+ :password, :password_confirmation, :email, :site_id, :notes, site_ids: [])
52
53
  end
53
54
 
54
55
  def announce_cannot_delete_self
@@ -0,0 +1,61 @@
1
+ class PageStatusController < ApplicationController
2
+ skip_before_action :verify_authenticity_token, only: [:refresh]
3
+ skip_before_action :authenticate_user!, only: [:refresh]
4
+ before_action :authenticate_bearer_token
5
+
6
+ def refresh
7
+ pages = Page.where(status_id: Status[:scheduled].id)
8
+
9
+ updated_pages, remaining_pages = process_pages(pages)
10
+
11
+ render json: refresh_response(updated_pages, remaining_pages), status: :ok
12
+ end
13
+
14
+ private
15
+
16
+ def authenticate_bearer_token
17
+ provided_token = request.headers['Authorization']&.split(' ')&.last
18
+ expected_token = Rails.application.credentials[:trusty_cms][:page_status_bearer_token]
19
+
20
+ if provided_token.blank?
21
+ render json: { error: 'Missing Bearer Token' }, status: :unauthorized and return
22
+ end
23
+
24
+ unless ActiveSupport::SecurityUtils.secure_compare(provided_token, expected_token)
25
+ render json: { error: 'Invalid Bearer Token' }, status: :unauthorized
26
+ end
27
+ end
28
+
29
+ def process_pages(pages)
30
+ updated_pages = []
31
+ remaining_pages = []
32
+
33
+ pages.each do |page|
34
+ page_id = page.id
35
+ if page.published_at <= Time.now
36
+ page.update(status_id: Status[:published].id)
37
+ updated_pages << page_id
38
+ else
39
+ remaining_pages << page_id
40
+ end
41
+ end
42
+
43
+ [updated_pages, remaining_pages]
44
+ end
45
+
46
+ def refresh_response(updated_pages, remaining_pages)
47
+ if updated_pages.any?
48
+ updated_pages_count = updated_pages.count
49
+ {
50
+ message: "Successfully updated status of #{updated_pages_count} #{'page'.pluralize(updated_pages_count)}.",
51
+ updated_page_ids: updated_pages,
52
+ remaining_scheduled_page_ids: remaining_pages,
53
+ }
54
+ else
55
+ {
56
+ message: 'No scheduled pages matched the criteria for status refresh.',
57
+ remaining_scheduled_page_ids: remaining_pages,
58
+ }
59
+ end
60
+ end
61
+ end
@@ -23,7 +23,6 @@ class SiteController < ApplicationController
23
23
  url.to_s
24
24
  end
25
25
  if @page = find_page(url)
26
- batch_page_status_refresh if url == '/' || url == ''
27
26
  # This is a bit of a hack to get Vanity URL pages working in another extension
28
27
  # In Rails 2, redirect_to halted execution, so process_page could be aliased and
29
28
  # a redirect could be used. This no longer works. There's a better fix for this,
@@ -61,20 +60,6 @@ class SiteController < ApplicationController
61
60
 
62
61
  private
63
62
 
64
- def batch_page_status_refresh
65
- @changed_pages = []
66
- @pages = Page.where({ status_id: Status[:scheduled].id })
67
- @pages.each do |page|
68
- if page.published_at <= Time.now
69
- page.status_id = Status[:published].id
70
- page.save
71
- @changed_pages << page.id
72
- end
73
- end
74
-
75
- expires_in nil, :private => true, 'no-cache' => true if @changed_pages.length > 0
76
- end
77
-
78
63
  def set_cache_control
79
64
  response_cache_director(@page).set_cache_control
80
65
  end
@@ -14,11 +14,6 @@ module Admin::PagesHelper
14
14
  !!(@page.errors[:slug] or @page.errors[:breadcrumb])
15
15
  end
16
16
 
17
- def status_to_display
18
- @page.status_id = 100 if @page.status_id == 90
19
- @display_status = Status.selectable.map { |s| [I18n.translate(s.name.downcase), s.id] }
20
- end
21
-
22
17
  def clean_page_description(page)
23
18
  page.description.to_s.strip.gsub(/\t/, '').gsub(/\s+/, ' ')
24
19
  end
@@ -2,7 +2,8 @@ module Admin::UsersHelper
2
2
  def roles(user)
3
3
  roles = []
4
4
  roles << I18n.t('admin') if user.admin?
5
- roles << I18n.t('designer') if user.designer?
5
+ roles << I18n.t('editor') if user.editor?
6
+ roles << I18n.t('content_editor') if user.content_editor?
6
7
  roles.join(', ')
7
8
  end
8
9
  end
@@ -33,11 +33,12 @@ module ApplicationHelper
33
33
  t('buttons.save_changes', default: 'Save Changes')
34
34
  options[:class] ||= 'button'
35
35
  options[:accesskey] ||= 'S'
36
+ options[:id] ||= 'save-button'
36
37
  submit_tag options.delete(:label), options
37
38
  end
38
39
 
39
40
  def save_model_and_continue_editing_button(_model)
40
- submit_tag t('buttons.save_and_continue'), name: 'continue', class: 'button', accesskey: 's'
41
+ submit_tag t('buttons.save_and_continue'), name: 'continue', class: 'button', accesskey: 's', id: 'save-and-continue-button'
41
42
  end
42
43
 
43
44
  def current_item?(item)
@@ -0,0 +1,6 @@
1
+ class AdminsSite < ActiveRecord::Base
2
+ self.table_name = 'admins_sites'
3
+
4
+ belongs_to :admin, class_name: 'User'
5
+ belongs_to :site
6
+ end
data/app/models/page.rb CHANGED
@@ -8,7 +8,7 @@ class Page < ActiveRecord::Base
8
8
  end
9
9
 
10
10
  # Callbacks
11
- before_save :update_virtual, :update_status, :set_allowed_children_cache
11
+ before_save :update_virtual, :update_published_datetime, :set_allowed_children_cache
12
12
 
13
13
  # Associations
14
14
  acts_as_tree order: 'position ASC'
@@ -220,15 +220,8 @@ class Page < ActiveRecord::Base
220
220
  slug_child
221
221
  end
222
222
 
223
- def update_status
224
- self.published_at = Time.zone.now if published? && published_at == nil
225
-
226
- if !published_at.nil? && (published? || scheduled?)
227
- self[:status_id] = Status[:scheduled].id if published_at > Time.zone.now
228
- self[:status_id] = Status[:published].id if published_at <= Time.zone.now
229
- end
230
-
231
- true
223
+ def update_published_datetime
224
+ self.published_at = Time.zone.now if published? && published_at.blank?
232
225
  end
233
226
 
234
227
  def default_child
data/app/models/site.rb CHANGED
@@ -7,6 +7,8 @@ class Site < ActiveRecord::Base
7
7
  belongs_to :created_by, class_name: 'User'
8
8
  belongs_to :updated_by, class_name: 'User'
9
9
  belongs_to :production_homepage, class_name: 'ProductionPage'
10
+ has_many :admins_sites
11
+ has_many :admins, through: :admins_sites, class_name: 'User'
10
12
 
11
13
  default_scope { order('position ASC') }
12
14
 
data/app/models/status.rb CHANGED
@@ -19,12 +19,8 @@ class Status
19
19
  @@statuses.find { |status| status.id.to_s == id.to_s }
20
20
  end
21
21
 
22
- def self.find_all
23
- @@statuses.dup
24
- end
25
-
26
22
  def self.selectable
27
- find_all - [self['Scheduled']]
23
+ @@statuses
28
24
  end
29
25
 
30
26
  def self.selectable_values
@@ -81,7 +81,8 @@ module TrustyCms
81
81
  TrustyCms::Config.initialize_cache
82
82
  end
83
83
  TrustyCms::Config.initialize_cache if TrustyCms::Config.stale_cache?
84
- Rails.cache.read('TrustyCms::Config')[key]
84
+ config_cache = Rails.cache.read('TrustyCms::Config')
85
+ config_cache ? config_cache[key] : nil
85
86
  end
86
87
  end
87
88
  end
data/app/models/user.rb CHANGED
@@ -7,7 +7,6 @@ class User < ActiveRecord::Base
7
7
  :recoverable, :rememberable, :trackable, :validatable
8
8
 
9
9
  alias_attribute :created_by_id, :id
10
-
11
10
  attr_accessor :skip_password_validation
12
11
 
13
12
  validate :password_complexity
@@ -18,6 +17,13 @@ class User < ActiveRecord::Base
18
17
  # Associations
19
18
  belongs_to :created_by, class_name: 'User'
20
19
  belongs_to :updated_by, class_name: 'User'
20
+ has_many :admins_sites, foreign_key: 'admin_id', class_name: 'AdminsSite', dependent: :destroy
21
+ has_many :sites, through: :admins_sites
22
+
23
+ # Roles
24
+ # Admin - all permissions
25
+ # Editor - all permissions except for users, sites editing
26
+ # Content Editor - all permissions except for users, sites, publishing and deleting
21
27
 
22
28
  def role?(role)
23
29
  case role
@@ -40,12 +46,16 @@ class User < ActiveRecord::Base
40
46
  designer
41
47
  end
42
48
 
49
+ def editor?
50
+ designer
51
+ end
52
+
43
53
  def content_editor?
44
54
  content_editor
45
55
  end
46
56
 
47
- def scoped?
48
- site_id.present?
57
+ def scoped_site?
58
+ sites.present?
49
59
  end
50
60
 
51
61
  def locale
@@ -67,4 +77,5 @@ class User < ActiveRecord::Base
67
77
 
68
78
  errors.add :password, 'Complexity requirement not met. Length should be 12 characters and include: 1 uppercase, 1 lowercase, 1 digit and 1 special character.'
69
79
  end
70
- end
80
+
81
+ end
@@ -1,7 +1,9 @@
1
1
  - unless current_user.site
2
2
  %label{:for=>'layout_site_id', :class => 'admin_only'}
3
3
  Site
4
- - sites = Site.all.map { |s| [s.name, s.id] }
5
- - selection = {:include_blank => Layout.is_shareable?}
6
- - selection[:selected] = current_site.id if @layout.new_record? && ! Layout.is_shareable?
4
+ :ruby
5
+ user_sites = current_user.admins_sites.pluck(:site_id)
6
+ sites = Site.where(:id => user_sites).map { |s| [s.name, s.id] }
7
+ selection = {:include_blank => Layout.is_shareable?}
8
+ selection[:selected] = current_site.id if @layout.new_record? && ! Layout.is_shareable?
7
9
  = select :layout, :site_id, sites, selection
@@ -1,9 +1,9 @@
1
- - if current_user.admin? && !current_user.scoped? && defined?(Site) && defined?(controller) && controller.sited_model? && controller.template_name == 'index' && Site.several?
1
+ - if current_user.scoped_site? && defined?(Site) && defined?(controller) && controller.sited_model? && controller.template_name == 'index' && Site.several?
2
2
  .site_chooser
3
3
  %ul.nav
4
4
  %li
5
5
  = "Current Site: #{current_site.name}"
6
6
  %ul.expansion
7
- - Site.all.each do |site|
7
+ - current_user.sites.each do |site|
8
8
  %li
9
9
  = link_to( site.name, "#{request.path}?site_id=#{site.id}", :class => site == current_site ? 'fg site-link' : 'site-link')
@@ -1,3 +1,5 @@
1
+ = javascript_include_tag 'admin/validations/scheduled_status_validation'
2
+
1
3
  = fields.hidden_field :lock_version
2
4
  = fields.hidden_field :parent_id
3
5
  = fields.hidden_field :class_name
@@ -41,16 +43,23 @@
41
43
  = fields.label :class_name, t('page_type')
42
44
  = fields.select :class_name, [[t('select.normal'), '']] + Page.descendants.map { |p| [p.display_name, p.name] }.sort_by { |p| p.first }
43
45
  - layout.edit_status do
44
- .status
45
- = fields.label :status_id, t('status')
46
- = fields.select :status_id, status_to_display
46
+ - if current_user.admin? || current_user.editor?
47
+ .status
48
+ = fields.label :status_id, t('status')
49
+ = fields.select :status_id, Status.selectable.map { |s| [s.name, s.id] }
47
50
  - layout.edit_published_at do
48
51
  .published-date
49
- #published_at{:class => (@page.published? ? nil : 'hidden')}
50
- = fields.label :published_at, t('published_on')
51
- = fields.text_field :published_at, :class=> 'date', :type=>'date', :value => (@page.published_at? ? I18n.localize(@page.published_at.to_date, :format =>:default) : nil)
52
+ #published_at{:class => (@page.published? ? '' : 'hidden')}
53
+ = fields.label :published_at, t('publish_datetime')
54
+ = fields.text_field :published_at,
55
+ class: 'datetime',
56
+ type: 'datetime-local',
57
+ value: (@page.published_at? ? @page.published_at.strftime('%Y-%m-%dT%H:%M') : nil)
52
58
  = render_region :layout_row, :locals => {:f => fields}
53
59
 
60
+ .error.hidden
61
+ %span#published-at-error
62
+
54
63
  - render_region :form_bottom, :locals => {:f => fields} do |form_bottom|
55
64
  - form_bottom.edit_buttons do
56
65
  - @buttons_partials.each do |partial|
@@ -18,5 +18,5 @@
18
18
  - unless simple
19
19
  %td.actions
20
20
  = page.add_child_option
21
- - if current_user.admin?
21
+ - if current_user.editor? || current_user.admin?
22
22
  = page.remove_option
@@ -1,5 +1,6 @@
1
1
  - unless current_user.site
2
2
  %label{:for=>'snippet_site_id', :Class => 'admin_only'}
3
3
  Site
4
- - sites = Site.all.map { |s| [s.name, s.id] }
4
+ - user_sites = current_user.admins_sites.pluck(:site_id)
5
+ - sites = Site.where(:id => user_sites).map { |s| [s.name, s.id] }
5
6
  = select :snippet, :site_id, sites, :include_blank => Snippet.is_shareable?, :selected => @snippet.site_id || current_site.id
@@ -1,4 +1,5 @@
1
1
  - if current_user.admin?
2
2
  %label{:for=>'user_admin'} Can edit site
3
- = select :user, :site_id, [['<any>', '']] + Site.all.map { |s| [s.name, s.id] }
3
+ .caption (hold ctrl or cmd to select multiple)
4
4
  .caption A user with no site is able to act (to whatever extent their status allows) on any site.
5
+ = select :user, :site_ids, options_for_select(Site.all.map { |s| [s.name, s.id] }, selected: @user.site_ids), {}, { multiple: true }
@@ -25,7 +25,9 @@
25
25
  = f.check_box 'admin', :class => 'checkbox'
26
26
  = f.label :admin, t('admin'), :class => 'checkbox'
27
27
  = f.check_box 'designer', :class => 'checkbox'
28
- = f.label :designer, t('designer'), :class => 'checkbox'
28
+ = f.label :designer, t('editor'), :class => 'checkbox'
29
+ = f.check_box 'content_editor', :class => 'checkbox'
30
+ = f.label :content_editor, t('content_editor'), :class => 'checkbox'
29
31
 
30
32
  - form.edit_notes do
31
33
  %fieldset
data/bin/rails CHANGED
@@ -3,8 +3,8 @@
3
3
  # installed from the root of your application.
4
4
 
5
5
  ENGINE_ROOT = File.expand_path('..', __dir__)
6
- ENGINE_PATH = File.expand_path('../lib/trusty/cms/engine', __dir__)
7
- APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
6
+ ENGINE_PATH = File.expand_path('../lib/trusty_cms/engine', __dir__)
7
+ APP_PATH = File.expand_path('../spec/dummy/config/application', __dir__)
8
8
 
9
9
  # Set up gems listed in the Gemfile.
10
10
  ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
@@ -20,6 +20,7 @@ module TrustyCms
20
20
  Rails.autoloaders.log!
21
21
  # Enable the asset pipeline
22
22
  config.assets.enabled = true
23
+ config.active_record.legacy_connection_handling = false
23
24
 
24
25
  # Version of your assets, change this if you want to expire all your assets
25
26
  config.assets.version = '1.0'
@@ -187,7 +187,7 @@ Devise.setup do |config|
187
187
  # ==> Configuration for :timeoutable
188
188
  # The time you want to timeout the user session without activity. After this
189
189
  # time the user will be asked for credentials again. Default is 30 minutes.
190
- # config.timeout_in = 30.minutes
190
+ config.timeout_in = 8.hours
191
191
 
192
192
  # ==> Configuration for :lockable
193
193
  # Defines which strategy will be used to lock an account.