effective_posts 1.1.10 → 2.0.2

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 (32) 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 +10 -29
  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/_recent_posts.html.haml +1 -4
  15. data/app/views/effective/posts/_sidebar.html.haml +1 -2
  16. data/app/views/effective/posts/show.html.haml +1 -2
  17. data/app/views/effective/posts/submitted.html.haml +1 -1
  18. data/config/effective_posts.rb +2 -37
  19. data/config/routes.rb +22 -28
  20. data/db/migrate/01_create_effective_posts.rb.erb +1 -2
  21. data/lib/effective_posts.rb +14 -50
  22. data/lib/effective_posts/engine.rb +1 -1
  23. data/lib/effective_posts/version.rb +1 -1
  24. metadata +9 -59
  25. data/app/assets/javascripts/effective/snippets/read_more_divider.js.coffee +0 -22
  26. data/app/helpers/effective_truncate_html_helper.rb +0 -73
  27. data/app/models/effective/access_denied.rb +0 -17
  28. data/app/models/effective/snippets/read_more_divider.rb +0 -11
  29. data/app/views/admin/posts/_actions.html.haml +0 -13
  30. data/app/views/admin/posts/edit.html.haml +0 -3
  31. data/app/views/admin/posts/new.html.haml +0 -3
  32. data/app/views/effective/snippets/_read_more_divider.html.haml +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5cfed91d21309be6bb55b1ddb763f7db0c0b0f84df48e58e1cebeeafd057cb0d
4
- data.tar.gz: 9efd9f25e107f6d4b3d3b9a04738b4e9e4f8453f341cb06d29ac7472d5740fe1
3
+ metadata.gz: 8aa5788677bbc314a5bf40d373e1d8fcd3ec888fcff06ceb309dc28b027304db
4
+ data.tar.gz: bc87d5b89781c026ee5db81ee123aeefbf5de29e8bd65c102e282c362b38ae2b
5
5
  SHA512:
6
- metadata.gz: a8f0693fd417027a7f0fe4e3f783f3ecb1d3db5a54342ee89087d7dff1cf0446b6be1f71e6c12df5edbac579df4e5eeca41da9db10bd3e3e0e7544fa7b6793c4
7
- data.tar.gz: fa1a3f84a24d1d93b3a86697791589c831d667fba94aa8a048229f84e96a48b39cafe06d8d0598ce864c7f3bb7a5c2e5f89ea50d620ac23b7a387fe68ae02aa8
6
+ metadata.gz: 175315b793aa0e096a29a20b66e568c93812ae804156e4c2bd169fa28ad20084041e0058f238fea7c063f87093d7f2e74330a2a15a10e47712470649ee7546b0
7
+ data.tar.gz: 2dc2137a2e10ec1c63e0cfbcfb63c92ee8b045568f8acb2ac991b7888eba0b4242ed7f9188f1c76cbd1b67ea4c423ada138798c02c85d47af7448bbf9eb98b07
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2018 Code and Effect Inc.
1
+ Copyright 2021 Code and Effect Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  A blog implementation with WYSIWYG content editing, post scheduling, pagination and optional top level routes for each post category.
4
4
 
5
- ## effective_posts 1.0
5
+ ## effective_posts 2.0
6
6
 
7
- This is the 1.0 series of effective_posts.
7
+ This is the 2.0 series of effective_posts.
8
8
 
9
- This requires Twitter Bootstrap 4 and Rails 5.1+
9
+ This requires Twitter Bootstrap 4 and Rails 6+
10
10
 
11
11
  Please check out [Effective Posts 0.x](https://github.com/code-and-effect/effective_posts/tree/bootstrap3) for more information using this gem with Bootstrap 3.
12
12
 
13
13
  ## Getting Started
14
14
 
15
- Please first install the [effective_regions](https://github.com/code-and-effect/effective_regions) and [effective_datatables](https://github.com/code-and-effect/effective_datatables) gems.
15
+ Please first install the [effective_datatables](https://github.com/code-and-effect/effective_datatables) gem.
16
16
 
17
17
  Please download and install [Twitter Bootstrap4](http://getbootstrap.com)
18
18
 
@@ -64,8 +64,6 @@ You can schedule a post to appear at a later date by setting the published_at va
64
64
 
65
65
  As well, if you're using the [effective_roles](https://github.com/code-and-effect/effective_roles) gem, you will be able to configure permissions so that only permitted users may view this post.
66
66
 
67
- Once you click `Save and Edit Content` you will be brought into the effective_regions editor where you may enter the content for your post. Click `Insert Snippet` -> `Read more divider` from the toolbar to place a divider into your post. Only the content above the Read more divider, the excerpt content, will be displayed on any posts#index screens. The full content will be displayed on the posts#show screen.
68
-
69
67
 
70
68
  ## Category Routes
71
69
 
@@ -78,9 +76,6 @@ If disabled, all posts will be available at `/posts`, with posts for a specific
78
76
 
79
77
  Use `link_to_post_category(:blog)` to display a link to the Blog page. The helper considers `config.use_category_routes` and puts in the correct url.
80
78
 
81
- Use `post_excerpt(post)` to display the excerpt for a post. Or `post_excerpt(post, :length => 200)` to truncate it and add a Read more link where appropriate.
82
-
83
-
84
79
  ## Pagination
85
80
 
86
81
  The [effective_bootstrap](https://github.com/code-and-effect/effective_bootstrap) gem is used for pagination on all posts#index type screens.
@@ -90,54 +85,7 @@ The per_page for posts may be configured via the `/app/config/initializers/effec
90
85
 
91
86
  ## Authorization
92
87
 
93
- All authorization checks are handled via the config.authorization_method found in the `app/config/initializers/effective_posts.rb` file.
94
-
95
- It is intended for flow through to CanCan or Pundit, but neither of those gems are required.
96
-
97
- This method is called by all controller actions with the appropriate action and resource
98
-
99
- Action will be one of [:index, :show, :new, :create, :edit, :update, :destroy]
100
-
101
- Resource will the appropriate Effective::Post object or class
102
-
103
- The authorization method is defined in the initializer file:
104
-
105
- ```ruby
106
- # As a Proc (with CanCan)
107
- config.authorization_method = Proc.new { |controller, action, resource| authorize!(action, resource) }
108
- ```
109
-
110
- ```ruby
111
- # As a Custom Method
112
- config.authorization_method = :my_authorization_method
113
- ```
114
-
115
- and then in your application_controller.rb:
116
-
117
- ```ruby
118
- def my_authorization_method(action, resource)
119
- current_user.is?(:admin) || EffectivePunditPolicy.new(current_user, resource).send('#{action}?')
120
- end
121
- ```
122
-
123
- or disabled entirely:
124
-
125
- ```ruby
126
- config.authorization_method = false
127
- ```
128
-
129
- If the method or proc returns false (user is not authorized) an Effective::AccessDenied exception will be raised
130
-
131
- You can rescue from this exception by adding the following to your application_controller.rb:
132
-
133
- ```ruby
134
- rescue_from Effective::AccessDenied do |exception|
135
- respond_to do |format|
136
- format.html { render 'static_pages/access_denied', :status => 403 }
137
- format.any { render :text => 'Access Denied', :status => 403 }
138
- end
139
- end
140
- ```
88
+ All authorization checks are handled via the effective_resources gem found in the `config/initializers/effective_resources.rb` file.
141
89
 
142
90
  ### Permissions
143
91
 
@@ -160,7 +108,6 @@ There are some obvious additional features that have yet to be implemented:
160
108
  - Some kind of helper for displaying a sidebar for the categories
161
109
  - Post archives and date filtering
162
110
 
163
-
164
111
  ## License
165
112
 
166
113
  MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
@@ -1,136 +1,21 @@
1
1
  module Admin
2
2
  class PostsController < ApplicationController
3
- before_action(:authenticate_user!) # Devise
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_posts) }
4
5
 
5
- layout (EffectivePosts.layout.kind_of?(Hash) ? EffectivePosts.layout[:admin] : EffectivePosts.layout)
6
+ include Effective::CrudController
6
7
 
7
- def index
8
- @page_title = 'Posts'
9
- @datatable = EffectivePostsDatatable.new(self)
10
-
11
- authorize_effective_posts!
12
- end
13
-
14
- def new
15
- @post = Effective::Post.new(published_at: Time.zone.now)
16
- @page_title = 'New Post'
17
-
18
- authorize_effective_posts!
19
- end
20
-
21
- def create
22
- @post = Effective::Post.new(post_params)
23
- @post.user = current_user if defined?(current_user)
24
-
25
- @page_title = 'New Post'
26
-
27
- authorize_effective_posts!
28
-
29
- if @post.save
30
- if params[:commit] == 'Save and Edit Content'
31
- redirect_to effective_regions.edit_path(effective_posts.post_path(@post), :exit => effective_posts.edit_admin_post_path(@post))
32
- elsif params[:commit] == 'Save and Add New'
33
- flash[:success] = 'Successfully created post'
34
- redirect_to effective_posts.new_admin_post_path
35
- elsif params[:commit] == 'Save and View'
36
- redirect_to effective_posts.post_path(@post)
37
- else
38
- flash[:success] = 'Successfully created post'
39
- redirect_to effective_posts.edit_admin_post_path(@post)
40
- end
41
- else
42
- flash.now[:danger] = 'Unable to create post'
43
- render :action => :new
44
- end
45
- end
46
-
47
- def edit
48
- @post = Effective::Post.find(params[:id])
49
- @page_title = 'Edit Post'
50
-
51
- authorize_effective_posts!
52
- end
53
-
54
- def update
55
- @post = Effective::Post.find(params[:id])
56
- @page_title = 'Edit Post'
57
-
58
- authorize_effective_posts!
59
-
60
- if @post.update_attributes(post_params)
61
- if params[:commit] == 'Save and Edit Content'
62
- redirect_to effective_regions.edit_path(effective_posts.post_path(@post), :exit => effective_posts.edit_admin_post_path(@post))
63
- elsif params[:commit] == 'Save and Add New'
64
- flash[:success] = 'Successfully updated post'
65
- redirect_to effective_posts.new_admin_post_path
66
- elsif params[:commit] == 'Save and View'
67
- redirect_to effective_posts.post_path(@post)
68
- elsif params[:commit] == 'Duplicate'
69
- begin
70
- post = @post.duplicate!
71
- flash[:success] = 'Successfully saved and duplicated post.'
72
- flash[:info] = "You are now editing the duplicated post. This new post has been created as a Draft."
73
- rescue => e
74
- flash.delete(:success)
75
- flash[:danger] = "Unable to duplicate post: #{e.message}"
76
- end
77
-
78
- redirect_to effective_posts.edit_admin_post_path(post || @post)
79
- else
80
- flash[:success] = 'Successfully updated post'
81
- redirect_to effective_posts.edit_admin_post_path(@post)
82
- end
83
- else
84
- flash.now[:danger] = 'Unable to update post'
85
- render :action => :edit
86
- end
87
- end
88
-
89
- def destroy
90
- @post = Effective::Post.find(params[:id])
91
-
92
- authorize_effective_posts!
93
-
94
- if @post.destroy
95
- flash[:success] = 'Successfully deleted post'
96
- else
97
- flash[:danger] = 'Unable to delete post'
98
- end
99
-
100
- redirect_to effective_posts.admin_posts_path
101
- end
102
-
103
- def approve
104
- @post = Effective::Post.find(params[:id])
105
- @page_title = 'Approve Post'
106
-
107
- authorize_effective_posts!
108
-
109
- if @post.update_attributes(draft: false)
110
- flash[:success] = 'Successfully approved post. It is now displayed on the website.'
111
- else
112
- flash[:danger] = "Unable to approve post: #{@post.errors.full_messages.join(', ')}"
113
- end
114
-
115
- redirect_to(:back) rescue redirect_to(effective_posts.admin_posts_path)
116
- end
117
-
118
- def excerpts
119
- @posts = Effective::Post.includes(:regions)
120
- @page_title = 'Post Excerpts'
121
-
122
- authorize_effective_posts!
8
+ if (config = EffectivePosts.layout)
9
+ layout(config.kind_of?(Hash) ? config[:admin] : config)
123
10
  end
124
11
 
125
- private
126
-
127
- def authorize_effective_posts!
128
- EffectivePosts.authorize!(self, :admin, :effective_posts)
129
- EffectivePosts.authorize!(self, action_name.to_sym, @post || Effective::Post)
130
- end
12
+ submit :save, 'Save'
13
+ submit :save, 'Save and Add New', redirect: :new
14
+ submit :save, 'Save and View', redirect: -> { effective_posts.post_path(resource) }
15
+ submit :save, 'Duplicate', redirect: -> { effective_posts.new_admin_post_path(duplicate_id: resource.id) }
131
16
 
132
17
  def post_params
133
- params.require(:effective_post).permit(EffectivePosts.permitted_params)
18
+ params.require(:effective_post).permit!
134
19
  end
135
20
 
136
21
  end
@@ -1,15 +1,21 @@
1
1
  module Effective
2
2
  class PostsController < ApplicationController
3
- layout (EffectivePosts.layout.kind_of?(Hash) ? EffectivePosts.layout[:posts] : EffectivePosts.layout)
3
+ if defined?(Devise)
4
+ before_action :authenticate_user!, only: [:new, :create, :edit, :update],
5
+ if: -> { EffectivePosts.submissions_require_current_user }
6
+ end
7
+
8
+ include Effective::CrudController
4
9
 
5
- before_action :authenticate_user!, only: [:new, :create, :edit, :update],
6
- if: -> { EffectivePosts.submissions_require_current_user }
10
+ if (config = EffectivePosts.layout)
11
+ layout(config.kind_of?(Hash) ? (config[:application] || config[:posts]) : config)
12
+ end
7
13
 
8
14
  def index
9
15
  @posts ||= Effective::Post.posts(
10
16
  user: current_user,
11
17
  category: params[:category],
12
- unpublished: EffectivePosts.authorized?(self, :admin, :effective_posts)
18
+ unpublished: EffectiveResources.authorized?(self, :admin, :effective_posts)
13
19
  )
14
20
 
15
21
  @posts = @posts.paginate(page: params[:page])
@@ -23,28 +29,27 @@ module Effective
23
29
  @posts = @posts.where(search) if search.present?
24
30
  end
25
31
 
26
- EffectivePosts.authorize!(self, :index, Effective::Post)
32
+ EffectiveResources.authorize!(self, :index, Effective::Post)
27
33
 
28
34
  @page_title ||= [(params[:category] || 'Blog').to_s.titleize, (" - Page #{params[:page]}" if params[:page])].compact.join
29
35
  @canonical_url ||= helpers.effective_post_category_url(params[:category], page: params[:page])
30
36
  end
31
37
 
32
38
  def show
33
- @posts ||= Effective::Post.posts(user: current_user, category: params[:category], unpublished: EffectivePosts.authorized?(self, :admin, :effective_posts))
39
+ @posts ||= Effective::Post.posts(user: current_user, category: params[:category], unpublished: EffectiveResources.authorized?(self, :admin, :effective_posts))
34
40
  @post = @posts.find(params[:id])
35
41
 
36
42
  if @post.respond_to?(:roles_permit?)
37
43
  raise Effective::AccessDenied.new('Access Denied', :show, @post) unless @post.roles_permit?(current_user)
38
44
  end
39
45
 
40
- EffectivePosts.authorize!(self, :show, @post)
46
+ EffectiveResources.authorize!(self, :show, @post)
41
47
 
42
- if EffectivePosts.authorized?(self, :admin, :effective_posts)
48
+ if EffectiveResources.authorized?(self, :admin, :effective_posts)
43
49
  flash.now[:warning] = [
44
50
  'Hi Admin!',
45
51
  ('You are viewing a hidden post.' unless @post.published?),
46
52
  'Click here to',
47
- ("<a href='#{effective_regions.edit_path(effective_posts.post_path(@post, exit: effective_posts.post_path(@post)))}' class='alert-link' data-no-turbolink='true' data-turbolinks='false'>edit post content</a> or" unless admin_edit?),
48
53
  ("<a href='#{effective_posts.edit_admin_post_path(@post)}' class='alert-link'>edit post settings</a>.")
49
54
  ].compact.join(' ')
50
55
  end
@@ -59,7 +64,7 @@ module Effective
59
64
  @post ||= Effective::Post.new(published_at: Time.zone.now)
60
65
  @page_title = 'New Post'
61
66
 
62
- EffectivePosts.authorize!(self, :new, @post)
67
+ EffectiveResources.authorize!(self, :new, @post)
63
68
  end
64
69
 
65
70
  def create
@@ -67,7 +72,7 @@ module Effective
67
72
  @post.user = current_user if defined?(current_user)
68
73
  @post.draft = (EffectivePosts.submissions_require_approval == true)
69
74
 
70
- EffectivePosts.authorize!(self, :create, @post)
75
+ EffectiveResources.authorize!(self, :create, @post)
71
76
 
72
77
  if @post.save
73
78
  @page_title ||= 'Post Submitted'
@@ -89,7 +94,7 @@ module Effective
89
94
  @post ||= Effective::Post.find(params[:id])
90
95
  @page_title ||= 'Edit Post'
91
96
 
92
- EffectivePosts.authorize!(self, :edit, @post)
97
+ EffectiveResources.authorize!(self, :edit, @post)
93
98
  end
94
99
 
95
100
  def update
@@ -97,7 +102,7 @@ module Effective
97
102
  draft_was = @post.draft
98
103
  @post.draft = (EffectivePosts.submissions_require_approval == true)
99
104
 
100
- EffectivePosts.authorize!(self, :update, @post)
105
+ EffectiveResources.authorize!(self, :update, @post)
101
106
 
102
107
  if @post.update_attributes(post_params)
103
108
  @page_title ||= 'Post Submitted'
@@ -118,7 +123,7 @@ module Effective
118
123
  def destroy
119
124
  @post ||= Effective::Post.find(params[:id])
120
125
 
121
- EffectivePosts.authorize!(self, :destroy, @post)
126
+ EffectiveResources.authorize!(self, :destroy, @post)
122
127
 
123
128
  if @post.destroy
124
129
  flash[:success] = 'Successfully deleted post'
@@ -136,7 +141,7 @@ module Effective
136
141
  end
137
142
 
138
143
  def admin_edit?
139
- EffectivePosts.authorized?(self, :admin, :effective_posts) && (params[:edit].to_s == 'true')
144
+ EffectiveResources.authorized?(self, :admin, :effective_posts) && (params[:edit].to_s == 'true')
140
145
  end
141
146
 
142
147
  end
@@ -25,7 +25,9 @@ class EffectivePostsDatatable < Effective::Datatable
25
25
 
26
26
  col :created_at, label: 'Submitted at', visible: false
27
27
 
28
- actions_col partial: '/admin/posts/actions', partial_as: :post
28
+ actions_col do |post|
29
+ dropdown_link_to('View', effective_post_path(post), target: '_blank')
30
+ end
29
31
  end
30
32
 
31
33
  collection do
@@ -3,7 +3,7 @@ require 'cgi'
3
3
  module EffectivePostsHelper
4
4
 
5
5
  def effective_posts_header_tags
6
- return unless @post.present? && @post.kind_of?(Effective::Post)
6
+ return unless @post && @post.kind_of?(Effective::Post) && @post.persisted?
7
7
 
8
8
  @effective_pages_og_type = 'article'
9
9
 
@@ -31,14 +31,15 @@ module EffectivePostsHelper
31
31
  def effective_post_category_path(category, opts = nil)
32
32
  return effective_posts.posts_path(opts || {}) unless category.present?
33
33
 
34
- category = category.to_s.downcase
34
+ category = category.to_s
35
+ category_path = category.to_s.downcase.parameterize
35
36
  opts = (opts || {}).compact
36
37
  query = ('?' + opts.to_query) if opts.present?
37
38
 
38
39
  if EffectivePosts.use_blog_routes
39
- "/blog/category/#{category}#{query}"
40
+ "/blog/category/#{category_path}#{query}"
40
41
  elsif EffectivePosts.use_category_routes
41
- "/#{category}#{query}"
42
+ "/#{category_path}#{query}"
42
43
  else
43
44
  effective_posts.posts_path(opts.merge(category: category.presence).compact)
44
45
  end
@@ -60,15 +61,15 @@ module EffectivePostsHelper
60
61
  def post_meta(post, date: true, datetime: false, category: true, author: true)
61
62
  [
62
63
  'Published',
63
- ("on #{post.published_at.strftime('%B %d, %Y')}" if date),
64
- ("on #{post.published_at.strftime('%B %d, %Y at %l:%M %p')}" if datetime),
64
+ ("on #{post.published_at.strftime('%B %d, %Y')}" if date && post.published_at),
65
+ ("on #{post.published_at.strftime('%B %d, %Y at %l:%M %p')}" if datetime && post.published_at),
65
66
  ("to #{link_to_post_category(post.category)}" if category && Array(EffectivePosts.categories).length > 1),
66
67
  ("by #{post.user.to_s.presence || 'Unknown'}" if author && EffectivePosts.post_meta_author && post.user.present?)
67
68
  ].compact.join(' ').html_safe
68
69
  end
69
70
 
70
71
  def admin_post_status_badge(post)
71
- return nil unless EffectivePosts.authorized?(self, :admin, :effective_posts)
72
+ return nil unless EffectiveResources.authorized?(self, :admin, :effective_posts)
72
73
 
73
74
  if post.draft?
74
75
  content_tag(:span, 'DRAFT', class: 'badge badge-info')
@@ -77,29 +78,9 @@ module EffectivePostsHelper
77
78
  end
78
79
  end
79
80
 
80
- # Only supported options are:
81
- # :label => 'Read more' to set the label of the 'Read More' link
82
- # :omission => '...' passed to the final text node's truncate
83
- # :length => 200 to set the max inner_text length of the content
84
81
  # All other options are passed to the link_to 'Read more'
85
- def post_excerpt(post, read_more_link: true, label: 'Continue reading', omission: '...', length: nil)
86
- content = effective_region(post, :body, editable: false) { '<p>Default content</p>'.html_safe }
87
- divider = content.index(Effective::Snippets::ReadMoreDivider::TOKEN)
88
- excerpt = post.excerpt.to_s
89
-
90
- read_more = (read_more_link && label.present?) ? readmore_link(post, label: label) : ''
91
-
92
- html = (
93
- if divider.present?
94
- truncate_html(content, Effective::Snippets::ReadMoreDivider::TOKEN, '')
95
- elsif length.present?
96
- truncate_html(excerpt, length, omission)
97
- else
98
- excerpt
99
- end
100
- ).html_safe
101
-
102
- (html + read_more).html_safe
82
+ def post_excerpt(post, label: 'Continue reading')
83
+ (post.excerpt.to_s + readmore_link(post, label: label)).html_safe
103
84
  end
104
85
 
105
86
  def read_more_link(post, options = {})