effective_posts 1.1.11 → 2.0.3

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 (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