effective_posts 1.2.0 → 2.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a7ad03cbc0f6be05bcd4b34bed730615b458bb9ae1438223edcef393fd3c107
4
- data.tar.gz: '028a4320fc0ec425c9fc4a2ec13e8cb38408fa63d0b9a8cc652a3fe7c1ba97e6'
3
+ metadata.gz: 850461d12290e86cc451412a56caaac5fccfc469c58d8a8a716f8b1efc1a0d40
4
+ data.tar.gz: 44069bc3c8563a6e91f467a7a9f1458d1cd0e6a3f79eb039abae1be473b76e7f
5
5
  SHA512:
6
- metadata.gz: 7ae7d9d8c4f85394b56e6915e4f8d21d7104753fb917e831f1d55011d74dedb3dafd1d743fdddc19859dd0145945645217aefbd70c53a93a0722a73bd06e0c76
7
- data.tar.gz: e3bad110e3c0cbbf0321e76bcd192b092d56318e0ca7bdd2e946793d2a170870a304266b10a38117b4f509864eae1d346d3647de1957bfeff7b92e7324512432
6
+ metadata.gz: 8cac1f40075ce9ad990c53ba9f4b0feb2bb887fe9a3b4931e0ed15b5ee574593537b1da261f728e84c08b588e0a2f68ad51a366f4949a93afd037f36b717ff15
7
+ data.tar.gz: fd63bde9093980a4f7e41660d6a11f7e317a52fe9ddaaace0b5addda9f6016138ff8feec88771f52ccf76c497b9b2a7715099714ef66ca7c4f8207b30e13930c
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.
@@ -1,136 +1,20 @@
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 View', redirect: -> { effective_posts.post_path(resource) }
14
+ submit :save, 'Duplicate', redirect: -> { effective_posts.new_admin_post_path(duplicate_id: resource.id) }
131
15
 
132
16
  def post_params
133
- params.require(:effective_post).permit(EffectivePosts.permitted_params)
17
+ params.require(:effective_post).permit!
134
18
  end
135
19
 
136
20
  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
 
@@ -69,7 +69,7 @@ module EffectivePostsHelper
69
69
  end
70
70
 
71
71
  def admin_post_status_badge(post)
72
- return nil unless EffectivePosts.authorized?(self, :admin, :effective_posts)
72
+ return nil unless EffectiveResources.authorized?(self, :admin, :effective_posts)
73
73
 
74
74
  if post.draft?
75
75
  content_tag(:span, 'DRAFT', class: 'badge badge-info')
@@ -78,29 +78,9 @@ module EffectivePostsHelper
78
78
  end
79
79
  end
80
80
 
81
- # Only supported options are:
82
- # :label => 'Read more' to set the label of the 'Read More' link
83
- # :omission => '...' passed to the final text node's truncate
84
- # :length => 200 to set the max inner_text length of the content
85
81
  # All other options are passed to the link_to 'Read more'
86
- def post_excerpt(post, read_more_link: true, label: 'Continue reading', omission: '...', length: nil)
87
- content = effective_region(post, :body, editable: false) { '<p>Default content</p>'.html_safe }
88
- divider = content.index(Effective::Snippets::ReadMoreDivider::TOKEN)
89
- excerpt = post.excerpt.to_s
90
-
91
- read_more = (read_more_link && label.present?) ? readmore_link(post, label: label) : ''
92
-
93
- html = (
94
- if divider.present?
95
- truncate_html(content, Effective::Snippets::ReadMoreDivider::TOKEN, '')
96
- elsif length.present?
97
- truncate_html(excerpt, length, omission)
98
- else
99
- excerpt
100
- end
101
- ).html_safe
102
-
103
- (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
104
84
  end
105
85
 
106
86
  def read_more_link(post, options = {})
@@ -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
18
+
19
+ effective_resource do
20
+ title :string
21
+ description :string
17
22
 
18
- # Attributes
19
- # title :string
20
- # description :string
23
+ category :string
24
+ slug :string
21
25
 
22
- # slug :string
26
+ draft :boolean
27
+ published_at :datetime
28
+ tags :text
23
29
 
24
- # category :string
30
+ roles_mask :integer
25
31
 
26
- # draft :boolean
27
- # published_at :datetime
28
- # tags :text
32
+ # Event Fields
33
+ start_at :datetime
34
+ end_at :datetime
29
35
 
30
- # roles_mask :integer
36
+ location :string
37
+ website_name :string
38
+ website_href :string
31
39
 
32
- # Event Fields
33
- # start_at :datetime
34
- # end_at :datetime
35
- # location :string
36
- # website_name :website_name
37
- # website_href :website_href
40
+ timestamps
41
+ end
38
42
 
39
- # timestamps
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
50
  validates :published_at, presence: true
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,25 +101,18 @@ 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] || raise('expected an EffectivePosts.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'
@@ -124,26 +121,15 @@ module Effective
124
121
  regions.each do |region|
125
122
  post.regions.build(region.attributes.except('id', 'updated_at', 'created_at'))
126
123
  end
127
-
128
- post.save!
129
124
  end
130
125
  end
131
126
 
132
- private
127
+ def duplicate!
128
+ duplicate.tap { |post| post.save! }
129
+ end
133
130
 
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
131
+ def approve!
132
+ update!(draft: false)
147
133
  end
148
134
 
149
135
  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.rich_text_area :excerpt, hint: 'Will be used for the post excerpt on index pages.'
8
+
9
+ = f.text_field :slug, required: f.object.persisted?,
10
+ 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
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,18 +27,12 @@
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
35
 
34
- - if EffectivePosts.use_fullscreen_editor
35
- = f.save 'Save and Edit Content', class: 'btn btn-secondary'
36
-
37
36
  = f.save 'Save and View', class: 'btn btn-secondary'
38
37
 
39
38
  - if f.object.persisted?
@@ -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
@@ -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,39 +29,8 @@ 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
@@ -107,8 +76,7 @@ EffectivePosts.setup do |config|
107
76
  default_from: 'info@example.com',
108
77
  admin_email: 'admin@example.com',
109
78
 
110
- deliver_method: nil, # :deliver (rails < 4.2), :deliver_now (rails >= 4.2) or :deliver_later
111
- delayed_job_deliver: false
79
+ deliver_method: :deliver_now
112
80
  }
113
81
 
114
82
  end
data/config/routes.rb CHANGED
@@ -1,15 +1,15 @@
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
+ if EffectivePosts.submissions_enabled && EffectivePosts.submissions_require_approval
5
+ post :approve, on: :member
6
+ end
7
7
  end
8
8
 
9
9
  match 'posts/excerpts', to: 'posts#excerpts', via: :get
10
10
  end
11
11
 
12
- scope :module => 'effective' do
12
+ scope module: 'effective' do
13
13
  categories = Array(EffectivePosts.categories).map { |cat| cat.to_s unless cat == 'posts'}.compact
14
14
  onlies = ([:index, :show] unless EffectivePosts.submissions_enabled)
15
15
 
@@ -33,9 +33,6 @@ EffectivePosts::Engine.routes.draw do
33
33
 
34
34
  end
35
35
 
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
36
+ Rails.application.routes.draw do
37
+ mount EffectivePosts::Engine => '/', :as => 'effective_posts'
41
38
  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,29 @@
1
- require 'nokogiri'
2
1
  require 'effective_datatables'
3
- require 'effective_regions'
2
+ require 'effective_resources'
4
3
  require 'effective_posts/engine'
5
4
  require 'effective_posts/version'
6
5
 
7
6
  module EffectivePosts
8
- mattr_accessor :posts_table_name
9
7
 
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
8
+ def self.config_keys
9
+ [
10
+ :posts_table_name, :layout, :categories,
11
+ :use_category_routes, :use_blog_routes,
12
+ :use_effective_roles, :use_fullscreen_editor, :use_active_storage,
13
+ :per_page, :post_meta_author,
14
+ :submissions_enabled, :submissions_require_current_user,
15
+ :submissions_require_approval, :submissions_note,
16
+ :mailer
17
+ ]
51
18
  end
52
19
 
53
- def self.authorize!(controller, action, resource)
54
- raise Effective::AccessDenied.new('Access Denied', action, resource) unless authorized?(controller, action, resource)
55
- end
20
+ include EffectiveGem
56
21
 
57
22
  def self.permitted_params
58
- [
23
+ [
59
24
  :title, :excerpt, :description, :draft, :category, :slug, :published_at, :body, :tags, :extra,
60
25
  :image, :start_at, :end_at, :location, :website_name, :website_href, roles: []
61
- ].compact
26
+ ]
62
27
  end
63
28
 
64
29
  end
@@ -10,7 +10,7 @@ module EffectivePosts
10
10
  end
11
11
 
12
12
  # Set up our default configuration options.
13
- initializer "effective_posts.defaults", :before => :load_config_initializers do |app|
13
+ initializer "effective_posts.defaults", before: :load_config_initializers do |app|
14
14
  # Set up our defaults, as per our initializer template
15
15
  eval File.read("#{config.root}/config/effective_posts.rb")
16
16
  end
@@ -1,3 +1,3 @@
1
1
  module EffectivePosts
2
- VERSION = '1.2.0'.freeze
2
+ VERSION = '2.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_posts
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 3.2.0
19
+ version: '6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 3.2.0
26
+ version: '6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: sass
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: nokogiri
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: effective_bootstrap
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +53,7 @@ dependencies:
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
- name: effective_ckeditor
56
+ name: effective_resources
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - ">="
@@ -82,34 +68,6 @@ dependencies:
82
68
  version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: effective_datatables
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: 4.0.0
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: 4.0.0
97
- - !ruby/object:Gem::Dependency
98
- name: effective_regions
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: effective_resources
113
71
  requirement: !ruby/object:Gem::Requirement
114
72
  requirements:
115
73
  - - ">="
@@ -132,7 +90,6 @@ extra_rdoc_files: []
132
90
  files:
133
91
  - MIT-LICENSE
134
92
  - README.md
135
- - app/assets/javascripts/effective/snippets/read_more_divider.js.coffee
136
93
  - app/assets/javascripts/effective_posts.js
137
94
  - app/assets/javascripts/effective_posts/additional_fields.js.coffee
138
95
  - app/assets/stylesheets/effective_posts.scss
@@ -140,18 +97,12 @@ files:
140
97
  - app/controllers/effective/posts_controller.rb
141
98
  - app/datatables/effective_posts_datatable.rb
142
99
  - app/helpers/effective_posts_helper.rb
143
- - app/helpers/effective_truncate_html_helper.rb
144
100
  - app/mailers/effective/posts_mailer.rb
145
- - app/models/effective/access_denied.rb
146
101
  - app/models/effective/post.rb
147
- - app/models/effective/snippets/read_more_divider.rb
148
- - app/views/admin/posts/_actions.html.haml
149
102
  - app/views/admin/posts/_form.html.haml
150
103
  - app/views/admin/posts/_roles.html.haml
151
- - app/views/admin/posts/edit.html.haml
152
104
  - app/views/admin/posts/excerpts.html.haml
153
105
  - app/views/admin/posts/index.html.haml
154
- - app/views/admin/posts/new.html.haml
155
106
  - app/views/effective/posts/_additional_fields.html.haml
156
107
  - app/views/effective/posts/_categories.html.haml
157
108
  - app/views/effective/posts/_event.html.haml
@@ -168,7 +119,6 @@ files:
168
119
  - app/views/effective/posts/show.html.haml
169
120
  - app/views/effective/posts/submitted.html.haml
170
121
  - app/views/effective/posts_mailer/post_submitted_to_admin.html.haml
171
- - app/views/effective/snippets/_read_more_divider.html.haml
172
122
  - app/views/layouts/effective_posts_mailer_layout.html.haml
173
123
  - config/effective_posts.rb
174
124
  - config/routes.rb
@@ -1,22 +0,0 @@
1
- CKEDITOR.dialog.add 'read_more_divider', (editor) -> # Must match the class name of the snippet
2
- title: 'Read more divider',
3
- minWidth: 200,
4
- minHeight: 100,
5
- contents: [
6
- {
7
- id: 'read_more_info', # Just an html id, doesn't really matter what is here
8
- elements: [
9
- {
10
- id: 'throwaway'
11
- type: 'html',
12
- html: 'Insert a read more divider to separate excerpt content from the full content.',
13
- setup: (widget) -> this.setValue(widget.data.throwaway)
14
- commit: (widget) -> widget.setData('throwaway', 'throwaway')
15
- },
16
- {
17
- type: 'html',
18
- html: 'Anything above the read more divider will be treated as excerpt content<br>and everything below the divider will also be included in the full content.'
19
- }
20
- ]
21
- }
22
- ]
@@ -1,73 +0,0 @@
1
- module EffectiveTruncateHtmlHelper
2
- # Truncates HTML or text to a certain inner_text character limit.
3
- #
4
- # If given HTML, the underlying markup may be much longer than length, but the displayed text
5
- # will be no longer than (length + omission) characters.
6
- def truncate_html(text, length_or_content = 200, omission = '...')
7
- doc = Nokogiri::HTML::DocumentFragment.parse(text)
8
-
9
- if length_or_content.kind_of?(String)
10
- content = (Nokogiri::HTML::DocumentFragment.parse(length_or_content).children.first.inner_text rescue length_or_content)
11
- doc.tap { |doc| _truncate_node_to_content(doc, content, omission) }.inner_html
12
- elsif length_or_content.kind_of?(Integer)
13
- doc.tap { |doc| _truncate_node_to_length(doc, length_or_content, omission) }.inner_html
14
- else
15
- raise 'Unsupported datatype passed to second argument of truncate_html. Expecting integer or string.'
16
- end
17
- end
18
-
19
- def _truncate_node_to_content(node, content, omission, seen = false)
20
- if seen == true
21
- node.remove
22
- elsif node.children.blank?
23
- index = node.content.index(content)
24
-
25
- if index.present?
26
- if node.parent.try(:content) == content # If my parent node just has my text in it, remove parent node too
27
- node.parent.remove
28
- elsif index == 0
29
- node.remove
30
- else
31
- node.content = truncate(node.content, length: index+omission.to_s.length, separator: ' ', omission: omission)
32
- end
33
-
34
- seen = true
35
- end
36
- else
37
- node.children.each { |child| seen = _truncate_node_to_content(child, content, omission, seen) }
38
- end
39
-
40
- seen
41
- end
42
-
43
-
44
- def _truncate_node_to_length(node, length, omission)
45
- if node.inner_text.length <= length
46
- # Do nothing, we're already reached base case
47
- elsif node.name == 'a'
48
- node.remove # I don't want to truncate anything in a link
49
- elsif node.children.blank?
50
- # I need to truncate myself, and I'm certainly a text node
51
- if node.text?
52
- node.content = truncate(node.content, length: length+omission.to_s.length, separator: ' ', omission: omission)
53
- else
54
- node.remove
55
- end
56
- else # Go through all the children, and delete anything after the length has been reached
57
- child_length = 0
58
-
59
- node.children.each do |child|
60
- child_length > length ? (child.remove) : (child_length += child.inner_text.length)
61
- end
62
-
63
- # We have now removed all nodes after length, but the last node is longer than our length
64
- # child_length is the inner_text length of all included nodes
65
- # And we only have to truncate the last child to get under length
66
-
67
- child = node.children.last
68
- child_max_length = length - (child_length - child.inner_text.length)
69
-
70
- _truncate_node_to_length(child, child_max_length, omission)
71
- end
72
- end
73
- end
@@ -1,17 +0,0 @@
1
- unless defined?(Effective::AccessDenied)
2
- module Effective
3
- class AccessDenied < StandardError
4
- attr_reader :action, :subject
5
-
6
- def initialize(message = nil, action = nil, subject = nil)
7
- @message = message
8
- @action = action
9
- @subject = subject
10
- end
11
-
12
- def to_s
13
- @message || I18n.t(:'unauthorized.default', :default => 'Access Denied')
14
- end
15
- end
16
- end
17
- end
@@ -1,11 +0,0 @@
1
- module Effective
2
- module Snippets
3
- class ReadMoreDivider < Snippet
4
- TOKEN = "<div style='display: none;'>READ_MORE_DIVIDER</div>"
5
-
6
- def snippet_attributes
7
- super + [:throwaway]
8
- end
9
- end
10
- end
11
- end
@@ -1,13 +0,0 @@
1
- = dropdown(variation: :dropleft) do
2
- - if datatable.admin_namespace?
3
- - if EffectivePosts.submissions_enabled && EffectivePosts.submissions_require_approval && !post.approved?
4
- = dropdown_link_to 'Approve', effective_posts.admin_approve_post_path(post)
5
-
6
- = dropdown_link_to 'Edit', effective_posts.edit_admin_post_path(post)
7
- - if EffectivePosts.use_fullscreen_editor
8
- = dropdown_link_to 'Edit Content', effective_post_path(post, edit: true), title: 'Edit Content', 'data-no-turbolink': true, 'data-turbolinks': false, target: '_blank'
9
-
10
- = dropdown_link_to 'View', effective_post_path(post), target: '_blank'
11
-
12
- = dropdown_link_to "Delete", effective_posts.admin_post_path(post),
13
- data: { method: :delete, confirm: "Really delete #{post}?" }
@@ -1,3 +0,0 @@
1
- %h1.effective-admin-heading= @page_title
2
-
3
- = render partial: 'form', as: :post, object: @post
@@ -1,3 +0,0 @@
1
- %h1.effective-admin-heading= @page_title
2
-
3
- = render partial: 'form', as: :post, object: @post
@@ -1,9 +0,0 @@
1
- - if effectively_editting?
2
- %p.show-block-adjust{:style => 'border-top: 2px dashed black; text-align: center;', :title => 'anything above this line will be treated as excerpt content'}
3
- %span{:style => 'background: #ddd; display: inline-block; padding: 0px 6px 4px 6px; border-radius: 0px 0px 10px 10px;'}
4
- Read more...
5
- - else
6
- = Effective::Snippets::ReadMoreDivider::TOKEN.html_safe
7
-
8
-
9
-