effective_posts 1.1.11 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +5 -58
  4. data/app/controllers/admin/posts_controller.rb +10 -125
  5. data/app/controllers/effective/posts_controller.rb +20 -15
  6. data/app/datatables/effective_posts_datatable.rb +3 -1
  7. data/app/helpers/effective_posts_helper.rb +12 -31
  8. data/app/mailers/effective/posts_mailer.rb +2 -1
  9. data/app/models/effective/post.rb +46 -61
  10. data/app/views/admin/posts/_form.html.haml +8 -11
  11. data/app/views/admin/posts/excerpts.html.haml +2 -2
  12. data/app/views/effective/posts/_form.html.haml +2 -3
  13. data/app/views/effective/posts/_post.html.haml +1 -1
  14. data/app/views/effective/posts/_sidebar.html.haml +1 -2
  15. data/app/views/effective/posts/show.html.haml +1 -2
  16. data/app/views/effective/posts/submitted.html.haml +1 -1
  17. data/config/effective_posts.rb +2 -37
  18. data/config/routes.rb +22 -28
  19. data/db/migrate/01_create_effective_posts.rb.erb +1 -2
  20. data/lib/effective_posts.rb +14 -50
  21. data/lib/effective_posts/engine.rb +1 -1
  22. data/lib/effective_posts/version.rb +1 -1
  23. metadata +5 -55
  24. data/app/assets/javascripts/effective/snippets/read_more_divider.js.coffee +0 -22
  25. data/app/helpers/effective_truncate_html_helper.rb +0 -73
  26. data/app/models/effective/access_denied.rb +0 -17
  27. data/app/models/effective/snippets/read_more_divider.rb +0 -11
  28. data/app/views/admin/posts/_actions.html.haml +0 -13
  29. data/app/views/admin/posts/edit.html.haml +0 -3
  30. data/app/views/admin/posts/new.html.haml +0 -3
  31. data/app/views/effective/snippets/_read_more_divider.html.haml +0 -9
@@ -10,7 +10,8 @@ module Effective
10
10
  mail(
11
11
  to: EffectivePosts.mailer[:admin_email],
12
12
  from: EffectivePosts.mailer[:default_from],
13
- subject: subject_for_post_submitted_to_admin(@post)
13
+ subject: subject_for_post_submitted_to_admin(@post),
14
+ tenant: (Tenant.current if defined?(Tenant))
14
15
  )
15
16
  end
16
17
 
@@ -1,55 +1,63 @@
1
1
  module Effective
2
2
  class Post < ActiveRecord::Base
3
- acts_as_regionable
3
+ attr_accessor :current_user
4
+
4
5
  acts_as_slugged
5
6
 
6
- if EffectivePosts.use_effective_roles && respond_to?(:acts_as_role_restricted)
7
- acts_as_role_restricted
8
- end
7
+ log_changes if respond_to?(:log_changes)
8
+ acts_as_role_restricted if respond_to?(:acts_as_role_restricted)
9
9
 
10
- if EffectivePosts.use_active_storage && respond_to?(:has_one_attached)
11
- has_one_attached :image
12
- end
10
+ has_one_attached :image
11
+
12
+ has_rich_text :excerpt
13
+ has_rich_text :body
13
14
 
14
15
  self.table_name = EffectivePosts.posts_table_name.to_s
15
16
 
16
- belongs_to :user, optional: true
17
+ belongs_to :user, polymorphic: true, optional: true
17
18
 
18
- # Attributes
19
- # title :string
20
- # description :string
19
+ effective_resource do
20
+ title :string
21
+ description :string
21
22
 
22
- # slug :string
23
+ category :string
24
+ slug :string
23
25
 
24
- # category :string
26
+ draft :boolean
27
+ published_at :datetime
28
+ tags :text
25
29
 
26
- # draft :boolean
27
- # published_at :datetime
28
- # tags :text
30
+ roles_mask :integer
29
31
 
30
- # roles_mask :integer
32
+ # Event Fields
33
+ start_at :datetime
34
+ end_at :datetime
31
35
 
32
- # Event Fields
33
- # start_at :datetime
34
- # end_at :datetime
35
- # location :string
36
- # website_name :website_name
37
- # website_href :website_href
36
+ location :string
37
+ website_name :string
38
+ website_href :string
38
39
 
39
- # timestamps
40
+ timestamps
41
+ end
42
+
43
+ before_validation(if: -> { current_user.present? }) do
44
+ self.user ||= current_user
45
+ end
40
46
 
41
47
  validates :title, presence: true, length: { maximum: 255 }
42
48
  validates :description, presence: true, length: { maximum: 150 }
43
49
  validates :category, presence: true
44
- validates :published_at, presence: true
50
+ validates :published_at, presence: true, unless: -> { draft? }
45
51
 
46
- validates :start_at, presence: true, if: -> { category == 'events'}
52
+ validates :start_at, presence: true, if: -> { category == 'events' }
47
53
 
48
54
  scope :drafts, -> { where(draft: true) }
49
55
  scope :published, -> { where(draft: false).where("#{EffectivePosts.posts_table_name}.published_at < ?", Time.zone.now) }
50
56
  scope :unpublished, -> { where(draft: true).or(where("#{EffectivePosts.posts_table_name}.published_at > ?", Time.zone.now)) }
51
57
  scope :with_category, -> (category) { where(category: category.to_s.downcase) }
52
58
 
59
+ scope :deep, -> { with_rich_text_excerpt_and_embeds.with_rich_text_body_and_embeds }
60
+
53
61
  scope :paginate, -> (page: nil, per_page: EffectivePosts.per_page) {
54
62
  page = (page || 1).to_i
55
63
  offset = [(page - 1), 0].max * per_page
@@ -58,7 +66,7 @@ module Effective
58
66
  }
59
67
 
60
68
  scope :posts, -> (user: nil, category: nil, unpublished: false) {
61
- scope = all.includes(:regions).order(published_at: :desc)
69
+ scope = all.deep.order(published_at: :desc)
62
70
 
63
71
  if defined?(EffectiveRoles) && EffectivePosts.use_effective_roles
64
72
  if user.present? && user.respond_to?(:roles)
@@ -77,16 +85,12 @@ module Effective
77
85
  scope
78
86
  }
79
87
 
80
- def to_param
81
- slug.presence || "#{id}-#{title.parameterize}"
82
- end
83
-
84
88
  def to_s
85
89
  title.presence || 'New Post'
86
90
  end
87
91
 
88
92
  def published?
89
- !draft? && published_at < Time.zone.now
93
+ !draft? && published_at.present? && published_at < Time.zone.now
90
94
  end
91
95
 
92
96
  def approved?
@@ -97,53 +101,34 @@ module Effective
97
101
  category == 'events'
98
102
  end
99
103
 
100
- def body
101
- region(:body).content
102
- end
103
-
104
- def body=(input)
105
- region(:body).content = input
106
- end
107
-
108
104
  # 3.333 words/second is the default reading speed.
109
105
  def time_to_read_in_seconds(reading_speed = 3.333)
110
106
  (regions.to_a.sum { |region| (region.content || '').scan(/\w+/).size } / reading_speed).seconds
111
107
  end
112
108
 
113
109
  def send_post_submitted_to_admin!
114
- send_email(:post_submitted_to_admin, to_param)
110
+ deliver_method = EffectivePosts.mailer[:deliver_method] || EffectiveResources.deliver_method
111
+ Effective::PostsMailer.post_submitted_to_admin(to_param).send(deliver_method)
115
112
  end
116
113
 
117
114
  # Returns a duplicated post object, or throws an exception
118
- def duplicate!
115
+ def duplicate
119
116
  Post.new(attributes.except('id', 'updated_at', 'created_at')).tap do |post|
120
117
  post.title = post.title + ' (Copy)'
121
118
  post.slug = post.slug + '-copy'
122
119
  post.draft = true
123
120
 
124
- regions.each do |region|
125
- post.regions.build(region.attributes.except('id', 'updated_at', 'created_at'))
126
- end
127
-
128
- post.save!
121
+ post.body = body
122
+ post.excerpt = excerpt
129
123
  end
130
124
  end
131
125
 
132
- private
126
+ def duplicate!
127
+ duplicate.tap { |post| post.save! }
128
+ end
133
129
 
134
- def send_email(email, *mailer_args)
135
- begin
136
- if EffectivePosts.mailer[:delayed_job_deliver] && EffectivePosts.mailer[:deliver_method] == :deliver_later
137
- Effective::PostsMailer.delay.public_send(email, *mailer_args)
138
- elsif EffectivePosts.mailer[:deliver_method].present?
139
- Effective::PostsMailer.public_send(email, *mailer_args).public_send(EffectivePosts.mailer[:deliver_method])
140
- else
141
- Effective::PostsMailer.public_send(email, *mailer_args).deliver_now
142
- end
143
- rescue => e
144
- raise e unless Rails.env.production?
145
- return false
146
- end
130
+ def approve!
131
+ update!(draft: false)
147
132
  end
148
133
 
149
134
  end
@@ -3,7 +3,13 @@
3
3
 
4
4
  - if f.object.persisted? || f.object.errors.include?(:slug)
5
5
  - current_url = effective_posts.post_path(f.object)
6
- = f.text_field :slug, hint: "The slug controls this post's internet address. Be careful, changing the slug will break links that other websites may have to the old address.<br>#{('This post is currently reachable via ' + link_to(current_url.gsub(f.object.slug, '<strong>' + f.object.slug + '</strong>').html_safe, current_url)) if current_url && f.object.slug.present? }".html_safe
6
+
7
+ = f.text_field :slug, required: f.object.persisted?,
8
+ hint: "The slug controls this post's internet address. Be careful, changing the slug will break links that other websites may have to the old address.<br>#{('This post is currently reachable via ' + link_to(current_url.gsub(f.object.slug, '<strong>' + f.object.slug + '</strong>').html_safe, current_url)) if current_url && f.object.slug.present? }".html_safe
9
+
10
+ = f.rich_text_area :excerpt, hint: 'Will be used for the post excerpt on index pages.'
11
+
12
+ = f.text_field :description, hint: 'The content of the post meta tags.', maxlength: 150
7
13
 
8
14
  - if Array(EffectivePosts.categories).length > 1
9
15
  = f.select :category, EffectivePosts.categories
@@ -13,8 +19,7 @@
13
19
  - if EffectivePosts.use_active_storage
14
20
  = f.file_field :image, hint: 'An image for your post'
15
21
 
16
- = f.ck_editor :excerpt, hint: 'Will be used for the post excerpt on index pages.'
17
- = f.text_field :description, hint: 'The content of the post meta tags.', maxlength: 150
22
+ = f.rich_text_area :body, hint: 'The main body of your post'
18
23
 
19
24
  = render partial: '/effective/posts/additional_fields', locals: { post: post, form: f, f: f }
20
25
 
@@ -22,19 +27,11 @@
22
27
 
23
28
  = f.check_box :draft, hint: 'Save this post as a draft. It will not be accessible on the website.'
24
29
 
25
- - unless EffectivePosts.use_fullscreen_editor
26
- = f.ck_editor :body, hint: 'The content of your post.'
27
-
28
30
  - if defined?(EffectiveRoles) && f.object.respond_to?(:roles) && EffectivePosts.use_effective_roles
29
31
  = render partial: '/admin/posts/roles', locals: { post: post, form: f, f: f }
30
32
 
31
33
  = f.submit do
32
34
  = f.save 'Save'
33
-
34
- - if EffectivePosts.use_fullscreen_editor
35
- = f.save 'Save and Edit Content', class: 'btn btn-secondary'
36
-
37
35
  = f.save 'Save and View', class: 'btn btn-secondary'
38
-
39
36
  - if f.object.persisted?
40
37
  = f.save 'Duplicate', class: 'btn btn-info'
@@ -6,10 +6,10 @@
6
6
  %h2.post-title= link_to post, effective_post_path(post)
7
7
  .row
8
8
  .col-sm-6
9
- %pre= effective_region(post, :body, editable: false)
9
+ %pre= post.body
10
10
 
11
11
  .col-sm-6
12
- %pre= post_excerpt(post)
12
+ %pre= post.excerpt
13
13
 
14
14
  .row
15
15
  .col-sm-12
@@ -13,7 +13,7 @@
13
13
  - if EffectivePosts.use_active_storage
14
14
  = f.file_field :image, hint: 'An image for your post'
15
15
 
16
- = f.ck_editor :excerpt, hint: 'Will be used for the post excerpt on index pages.'
16
+ = f.rich_text_area :excerpt, hint: 'Will be used for the post excerpt on index pages.'
17
17
  = f.text_field :description, hint: 'The content of the post meta tags.', maxlength: 150
18
18
 
19
19
  = render partial: '/effective/posts/additional_fields', locals: { post: post, form: f, f: f }
@@ -22,7 +22,6 @@
22
22
 
23
23
  = f.check_box :draft, hint: 'Save this post as a draft. It will not be accessible on the website.'
24
24
 
25
- - unless EffectivePosts.use_fullscreen_editor
26
- = f.ck_editor :body, hint: 'The content of your post.'
25
+ = f.rich_text_area :body, hint: 'The main body of your post'
27
26
 
28
27
  = f.submit 'Save'
@@ -6,4 +6,4 @@
6
6
  = admin_post_status_badge(post)
7
7
 
8
8
  .post-content.post-excerpt
9
- = post_excerpt(post)
9
+ = post.excerpt
@@ -18,11 +18,10 @@
18
18
  - if posts.length == 0
19
19
  %li= link_to 'None', effective_posts.posts_path, class: 'disabled'
20
20
 
21
- - if EffectivePosts.authorized?(self, :admin, :effective_posts)
21
+ - if EffectiveResources.authorized?(self, :admin, :effective_posts)
22
22
  %h4.dashboard-title Admin
23
23
  %ul.list-unstyled
24
24
  %li= link_to 'All Posts', effective_posts.admin_posts_path
25
25
 
26
26
  - if @post.present?
27
- %li= link_to 'Edit Post Content', effective_regions.edit_path(effective_posts.post_path(@post, exit: effective_posts.post_path(@post)))
28
27
  %li= link_to 'Edit Post Settings', effective_posts.edit_admin_post_path(@post)
@@ -9,5 +9,4 @@
9
9
  = render 'effective/posts/event', post: @post
10
10
 
11
11
  .post-body.post-content
12
- = effective_region @post, :body do
13
- %p Default content
12
+ = @post.body
@@ -2,7 +2,7 @@
2
2
 
3
3
  %p= EffectivePosts.submissions_note
4
4
 
5
- - if EffectivePosts.authorized?(controller, :edit, @post)
5
+ - if EffectiveResources.authorized?(controller, :edit, @post)
6
6
  %p= link_to 'Edit Post', effective_posts.edit_post_path(@post), class: 'btn btn-primary btn-edit-post'
7
7
 
8
8
  %hr
@@ -29,46 +29,12 @@ EffectivePosts.setup do |config|
29
29
  # The author is the user that created the Effective::Post object
30
30
  config.post_meta_author = true
31
31
 
32
- # Authorization Method
33
- #
34
- # This method is called by all controller actions with the appropriate action and resource
35
- # If the method returns false, an Effective::AccessDenied Error will be raised (see README.md for complete info)
36
- #
37
- # Use via Proc (and with CanCan):
38
- # config.authorization_method = Proc.new { |controller, action, resource| can?(action, resource) }
39
- #
40
- # Use via custom method:
41
- # config.authorization_method = :my_authorization_method
42
- #
43
- # And then in your application_controller.rb:
44
- #
45
- # def my_authorization_method(action, resource)
46
- # current_user.is?(:admin)
47
- # end
48
- #
49
- # Or disable the check completely:
50
- # config.authorization_method = false
51
- config.authorization_method = Proc.new do |controller, action, resource|
52
- authorize!(action, resource)
53
- resource.respond_to?(:roles_permit?) ? resource.roles_permit?(current_user) : true
54
- end
55
-
56
32
  # Layout Settings
57
- # Configure the Layout per controller, or all at once
58
- config.layout = {
59
- posts: 'application',
60
- admin: 'admin'
61
- }
62
-
63
- # Add additional permitted params
64
- # config.permitted_params += [:additional_field]
33
+ # config.layout = { application: 'application', admin: 'admin' }
65
34
 
66
35
  # Display the effective roles 'choose roles' input when an admin creates a new post
67
36
  config.use_effective_roles = false
68
37
 
69
- # Hides the Save and Edit Content links from admin. They can just use the textarea input.
70
- config.use_fullscreen_editor = true
71
-
72
38
  # Display a file upload field when the admin creates a new post to collect a post.image
73
39
  config.use_active_storage = true
74
40
 
@@ -107,8 +73,7 @@ EffectivePosts.setup do |config|
107
73
  default_from: 'info@example.com',
108
74
  admin_email: 'admin@example.com',
109
75
 
110
- deliver_method: nil, # :deliver (rails < 4.2), :deliver_now (rails >= 4.2) or :deliver_later
111
- delayed_job_deliver: false
76
+ deliver_method: :deliver_now
112
77
  }
113
78
 
114
79
  end
data/config/routes.rb CHANGED
@@ -1,41 +1,35 @@
1
1
  EffectivePosts::Engine.routes.draw do
2
2
  namespace :admin do
3
- resources :posts, except: [:show]
4
-
5
- if EffectivePosts.submissions_enabled && EffectivePosts.submissions_require_approval
6
- match 'posts/:id/approve', to: 'posts#approve', via: :get, as: :approve_post
3
+ resources :posts, except: [:show] do
4
+ post :approve, on: :member
7
5
  end
8
-
9
- match 'posts/excerpts', to: 'posts#excerpts', via: :get
10
6
  end
11
7
 
12
- scope :module => 'effective' do
13
- categories = Array(EffectivePosts.categories).map { |cat| cat.to_s unless cat == 'posts'}.compact
14
- onlies = ([:index, :show] unless EffectivePosts.submissions_enabled)
8
+ scope module: 'effective' do
9
+ # Post Routes
10
+ resources :posts
15
11
 
16
- if EffectivePosts.use_blog_routes
17
- categories.each do |category|
18
- match "blog/category/#{category}", to: 'posts#index', via: :get, defaults: { category: category }
19
- end
12
+ # Blog Routes
13
+ match 'blog/category/:category', to: 'posts#index', via: :get, constraints: lambda { |req|
14
+ EffectivePosts.use_blog_routes && EffectivePosts.categories.include?(req.params['category'].to_sym)
15
+ }
20
16
 
21
- resources :posts, only: onlies, path: 'blog'
22
- elsif EffectivePosts.use_category_routes
23
- categories.each do |category|
24
- match category, to: 'posts#index', via: :get, defaults: { category: category }
25
- match "#{category}/:id", to: 'posts#show', via: :get, defaults: { category: category }
26
- end
17
+ resources :posts, only: [:index, :show], path: 'blog', constraints: lambda { |req|
18
+ EffectivePosts.use_blog_routes
19
+ }
27
20
 
28
- resources :posts, only: onlies
29
- else
30
- resources :posts, only: onlies
31
- end
21
+ # Category routes
22
+ match ':category', to: 'posts#index', via: :get, constraints: lambda { |req|
23
+ EffectivePosts.use_category_routes && EffectivePosts.categories.include?(req.params['category'].to_sym)
24
+ }
25
+
26
+ match ":category/:id", to: 'posts#show', via: :get, constraints: lambda { |req|
27
+ EffectivePosts.use_category_routes && EffectivePosts.categories.include?(req.params['category'].to_sym)
28
+ }
32
29
  end
33
30
 
34
31
  end
35
32
 
36
- # Automatically mount the engine as an append
37
- Rails.application.routes.append do
38
- unless Rails.application.routes.routes.find { |r| r.name == 'effective_posts' }
39
- mount EffectivePosts::Engine => '/', :as => 'effective_posts'
40
- end
33
+ Rails.application.routes.draw do
34
+ mount EffectivePosts::Engine => '/', as: 'effective_posts'
41
35
  end
@@ -2,10 +2,9 @@ class CreateEffectivePosts < ActiveRecord::Migration[4.2]
2
2
  def self.up
3
3
  create_table <%= @posts_table_name %> do |t|
4
4
  t.integer :user_id
5
+ t.string :user_type
5
6
 
6
7
  t.string :title
7
- t.text :excerpt
8
-
9
8
  t.string :description
10
9
 
11
10
  t.string :category
@@ -1,64 +1,28 @@
1
- require 'nokogiri'
2
- require 'effective_datatables'
3
- require 'effective_regions'
1
+ require 'effective_resources'
4
2
  require 'effective_posts/engine'
5
3
  require 'effective_posts/version'
6
4
 
7
5
  module EffectivePosts
8
- mattr_accessor :posts_table_name
9
6
 
10
- mattr_accessor :authorization_method
11
- mattr_accessor :permitted_params
12
-
13
- mattr_accessor :layout
14
- mattr_accessor :simple_form_options
15
- mattr_accessor :admin_simple_form_options
16
-
17
- mattr_accessor :categories
18
- mattr_accessor :use_category_routes
19
- mattr_accessor :use_blog_routes
20
-
21
- mattr_accessor :use_effective_roles
22
- mattr_accessor :use_fullscreen_editor
23
- mattr_accessor :use_active_storage
24
-
25
- mattr_accessor :per_page
26
- mattr_accessor :post_meta_author
27
-
28
- mattr_accessor :submissions_enabled
29
- mattr_accessor :submissions_require_current_user
30
- mattr_accessor :submissions_require_approval
31
- mattr_accessor :submissions_note
32
-
33
- # These are hashes of configs
34
- mattr_accessor :mailer
35
-
36
- def self.setup
37
- yield self
38
- end
39
-
40
- def self.authorized?(controller, action, resource)
41
- @_exceptions ||= [Effective::AccessDenied, (CanCan::AccessDenied if defined?(CanCan)), (Pundit::NotAuthorizedError if defined?(Pundit))].compact
42
-
43
- return !!authorization_method unless authorization_method.respond_to?(:call)
44
- controller = controller.controller if controller.respond_to?(:controller)
45
-
46
- begin
47
- !!(controller || self).instance_exec((controller || self), action, resource, &authorization_method)
48
- rescue *@_exceptions
49
- false
50
- end
7
+ def self.config_keys
8
+ [
9
+ :posts_table_name, :layout, :categories,
10
+ :use_category_routes, :use_blog_routes,
11
+ :use_effective_roles, :use_active_storage,
12
+ :per_page, :post_meta_author,
13
+ :submissions_enabled, :submissions_require_current_user,
14
+ :submissions_require_approval, :submissions_note,
15
+ :mailer
16
+ ]
51
17
  end
52
18
 
53
- def self.authorize!(controller, action, resource)
54
- raise Effective::AccessDenied.new('Access Denied', action, resource) unless authorized?(controller, action, resource)
55
- end
19
+ include EffectiveGem
56
20
 
57
21
  def self.permitted_params
58
- [
22
+ @permitted_params ||= [
59
23
  :title, :excerpt, :description, :draft, :category, :slug, :published_at, :body, :tags, :extra,
60
24
  :image, :start_at, :end_at, :location, :website_name, :website_href, roles: []
61
- ].compact
25
+ ]
62
26
  end
63
27
 
64
28
  end