effective_posts 0.4.6 → 0.4.7

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/app/controllers/admin/posts_controller.rb +18 -5
  3. data/app/controllers/effective/posts_controller.rb +87 -17
  4. data/app/helpers/effective_posts_helper.rb +43 -16
  5. data/app/mailers/effective/posts_mailer.rb +34 -0
  6. data/app/models/effective/datatables/posts.rb +14 -4
  7. data/app/models/effective/post.rb +63 -5
  8. data/app/views/admin/posts/_actions.html.haml +16 -9
  9. data/app/views/admin/posts/_form.html.haml +28 -21
  10. data/app/views/admin/posts/edit.html.haml +1 -1
  11. data/app/views/admin/posts/excerpts.html.haml +1 -1
  12. data/app/views/admin/posts/new.html.haml +1 -1
  13. data/app/views/effective/posts/_additional_fields.html.haml +2 -0
  14. data/app/views/effective/posts/_categories.html.haml +4 -0
  15. data/app/views/effective/posts/_form.html.haml +27 -0
  16. data/app/views/effective/posts/_recent_posts.html.haml +5 -0
  17. data/app/views/effective/posts/_spacer.html.haml +1 -0
  18. data/app/views/effective/posts/edit.html.haml +2 -0
  19. data/app/views/effective/posts/index.html.haml +7 -2
  20. data/app/views/effective/posts/new.html.haml +2 -0
  21. data/app/views/effective/posts/show.html.haml +3 -3
  22. data/app/views/effective/posts/submitted.html.haml +10 -0
  23. data/app/views/effective/posts_mailer/post_submitted_to_admin.html.haml +22 -0
  24. data/app/views/layouts/effective_posts_mailer_layout.html.haml +7 -0
  25. data/config/routes.rb +12 -7
  26. data/lib/effective_posts.rb +19 -1
  27. data/lib/effective_posts/version.rb +1 -1
  28. data/lib/generators/effective_posts/install_generator.rb +10 -0
  29. data/lib/generators/templates/effective_posts.rb +52 -9
  30. data/lib/generators/templates/effective_posts_mailer_preview.rb +22 -0
  31. metadata +36 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 11c1c38bb1cb3976cf832a0e195990c8ec092ce3
4
- data.tar.gz: e7c14e2c912bb93409deb13bef22ec6128b89c8e
3
+ metadata.gz: b6c0cbc8c247c67715094aba5e52ea2f212cdbe3
4
+ data.tar.gz: a67ae4457e20eb7675c78dc1c769a1b1cc84595b
5
5
  SHA512:
6
- metadata.gz: 5793b3006b5dc1583d20a24bad119c9cc478a0fa53f281fcea25148c212ac74ea720da4ca8490a6c05481ea9412aea7f7892d87c0b7bde459e3277b6709ff49a
7
- data.tar.gz: 613e891c1f32be3c11e7bb4ccb23ecd59be1ed8b06795843dc5bbaab04ed41175a50a88cbc8b5eb86d20506808f0faffea4512a0ca33061358b7556a74e3ed3b
6
+ metadata.gz: 1999a9f99ca390aab1e0576f8a1d5df86b0d33ccc7b29ea66b3903dd69777ac0ba29341a91f18abd1dc9e8360c98f5409d93cdeb4fe5f088d861cff8ae6b27e0
7
+ data.tar.gz: b09a6b63101b33d938f70230485668f0c2c1dd1b34d1bd01650a04757c9aa01d1943e9a5226af362d4826bff0ba9f4931bcb2d04b3621a7946b65956872eba3c
@@ -12,7 +12,7 @@ module Admin
12
12
  end
13
13
 
14
14
  def new
15
- @post = Effective::Post.new(:published_at => Time.zone.now)
15
+ @post = Effective::Post.new(published_at: Time.zone.now)
16
16
  @page_title = 'New Post'
17
17
 
18
18
  EffectivePosts.authorized?(self, :new, @post)
@@ -30,6 +30,7 @@ module Admin
30
30
  if params[:commit] == 'Save and Edit Content' && defined?(EffectiveRegions)
31
31
  redirect_to effective_regions.edit_path(effective_posts.post_path(@post), :exit => effective_posts.edit_admin_post_path(@post))
32
32
  elsif params[:commit] == 'Save and Add New'
33
+ flash[:success] = 'Successfully created post'
33
34
  redirect_to effective_posts.new_admin_post_path
34
35
  else
35
36
  flash[:success] = 'Successfully created post'
@@ -58,6 +59,7 @@ module Admin
58
59
  if params[:commit] == 'Save and Edit Content' && defined?(EffectiveRegions)
59
60
  redirect_to effective_regions.edit_path(effective_posts.post_path(@post), :exit => effective_posts.edit_admin_post_path(@post))
60
61
  elsif params[:commit] == 'Save and Add New'
62
+ flash[:success] = 'Successfully updated post'
61
63
  redirect_to effective_posts.new_admin_post_path
62
64
  else
63
65
  flash[:success] = 'Successfully updated post'
@@ -83,6 +85,20 @@ module Admin
83
85
  redirect_to effective_posts.admin_posts_path
84
86
  end
85
87
 
88
+ def approve
89
+ @post = Effective::Post.find(params[:id])
90
+
91
+ EffectivePosts.authorized?(self, :approve, @post)
92
+
93
+ if @post.update_attributes(draft: false)
94
+ flash[:success] = 'Successfully approved post. It is now displayed on the website.'
95
+ else
96
+ flash[:danger] = "Unable to approve post: #{@post.errors.full_messages.join(', ')}"
97
+ end
98
+
99
+ redirect_to(:back) rescue redirect_to(effective_posts.admin_posts_path)
100
+ end
101
+
86
102
  def excerpts
87
103
  @page_title = 'Post Excerpts'
88
104
 
@@ -91,13 +107,10 @@ module Admin
91
107
  @posts = Effective::Post.includes(:regions)
92
108
  end
93
109
 
94
-
95
110
  private
96
111
 
97
112
  def post_params
98
- params.require(:effective_post).permit(
99
- :title, :draft, :category, :published_at, :roles => []
100
- )
113
+ params.require(:effective_post).permit(EffectivePosts.permitted_params)
101
114
  end
102
115
 
103
116
  end
@@ -2,34 +2,25 @@ module Effective
2
2
  class PostsController < ApplicationController
3
3
  layout (EffectivePosts.layout.kind_of?(Hash) ? EffectivePosts.layout[:posts] : EffectivePosts.layout)
4
4
 
5
- after_action :monkey_patch_for_kaminari, :only => [:index]
5
+ before_action :authenticate_user!, only: [:new, :create, :edit, :update],
6
+ if: -> { EffectivePosts.submissions_require_current_user }
6
7
 
7
- def index
8
- @posts = (Rails::VERSION::MAJOR > 3 ? Effective::Post.all : Effective::Post.scoped)
9
-
10
- @posts = @posts.for_role(current_user.try(:roles)) if defined?(EffectiveRoles)
11
- @posts = @posts.with_category(params[:category]) if params[:category]
12
- @posts = @posts.published
13
- @posts = @posts.includes(:regions)
8
+ after_action :monkey_patch_for_kaminari, only: [:index]
14
9
 
15
- @posts = @posts.order("#{EffectivePosts.posts_table_name}.published_at DESC")
10
+ def index
11
+ @posts ||= Effective::Post.posts(user: current_user, category: params[:category])
16
12
  @posts = @posts.page(params[:page]).per(EffectivePosts.per_page)
17
13
 
18
14
  EffectivePosts.authorized?(self, :index, Effective::Post)
19
15
 
20
- @page_title = (params[:category] || 'Posts').titleize
16
+ @page_title = (params[:page_title] || params[:category] || 'Posts').titleize
21
17
  end
22
18
 
23
19
  def show
24
- @posts = (Rails::VERSION::MAJOR > 3 ? Effective::Post.all : Effective::Post.scoped)
25
-
26
- @posts = @posts.with_category(params[:category]) if params[:category]
27
- @posts = @posts.published if params[:edit].to_s != 'true'
28
- @posts = @posts.includes(:regions)
29
-
20
+ @posts ||= Effective::Post.posts(user: current_user, category: params[:category], drafts: (params[:edit].to_s == 'true' || params[:preview].to_s == 'true'))
30
21
  @post = @posts.find(params[:id])
31
22
 
32
- if defined?(EffectiveRoles)
23
+ if @post.respond_to?(:roles_permit?)
33
24
  raise Effective::AccessDenied unless @post.roles_permit?(current_user)
34
25
  end
35
26
 
@@ -38,8 +29,87 @@ module Effective
38
29
  @page_title = @post.title
39
30
  end
40
31
 
32
+ # Public user submit a post functionality
33
+ def new
34
+ @post ||= Effective::Post.new(published_at: Time.zone.now)
35
+ @page_title = 'New Post'
36
+
37
+ EffectivePosts.authorized?(self, :new, @post)
38
+ end
39
+
40
+ def create
41
+ @post ||= Effective::Post.new(post_params)
42
+ @post.user = current_user if defined?(current_user)
43
+ @post.draft = (EffectivePosts.submissions_require_approval == true)
44
+
45
+ EffectivePosts.authorized?(self, :create, @post)
46
+
47
+ if @post.save
48
+ @page_title ||= 'Post Submitted'
49
+ flash.now[:success] = 'Successfully submitted post'
50
+
51
+ if EffectivePosts.submissions_require_approval
52
+ @post.send_post_submitted_to_admin!
53
+ end
54
+
55
+ render :submitted
56
+ else
57
+ @page_title ||= 'New Post'
58
+ flash.now[:danger] = 'Unable to submit post'
59
+ render action: :new
60
+ end
61
+ end
62
+
63
+ def edit
64
+ @post ||= Effective::Post.find(params[:id])
65
+ @page_title ||= 'Edit Post'
66
+
67
+ EffectivePosts.authorized?(self, :edit, @post)
68
+ end
69
+
70
+ def update
71
+ @post ||= Effective::Post.find(params[:id])
72
+ draft_was = @post.draft
73
+ @post.draft = (EffectivePosts.submissions_require_approval == true)
74
+
75
+ EffectivePosts.authorized?(self, :update, @post)
76
+
77
+ if @post.update_attributes(post_params)
78
+ @page_title ||= 'Post Submitted'
79
+ flash.now[:success] = 'Successfully re-submitted post'
80
+
81
+ if EffectivePosts.submissions_require_approval && draft_was != true
82
+ @post.send_post_submitted_to_admin!
83
+ end
84
+
85
+ render :submitted
86
+ else
87
+ @page_title ||= 'Edit Post'
88
+ flash.now[:danger] = 'Unable to update post'
89
+ render action: :edit
90
+ end
91
+ end
92
+
93
+ def destroy
94
+ @post ||= Effective::Post.find(params[:id])
95
+
96
+ EffectivePosts.authorized?(self, :destroy, @post)
97
+
98
+ if @post.destroy
99
+ flash[:success] = 'Successfully deleted post'
100
+ else
101
+ flash[:danger] = 'Unable to delete post'
102
+ end
103
+
104
+ redirect_to effective_posts.posts_path
105
+ end
106
+
41
107
  private
42
108
 
109
+ def post_params
110
+ params.require(:effective_post).permit(EffectivePosts.permitted_params)
111
+ end
112
+
43
113
  def monkey_patch_for_kaminari
44
114
  @template = @template.tap { |template| template.extend(EffectiveKaminariHelper) }
45
115
  end
@@ -1,6 +1,17 @@
1
1
  require 'cgi'
2
2
 
3
3
  module EffectivePostsHelper
4
+ def effective_post_path(post, opts = nil)
5
+ category = post.category.to_s.downcase
6
+ opts ||= {}
7
+
8
+ if EffectivePosts.use_category_routes
9
+ "/#{category}" + effective_posts.post_path(post, opts)
10
+ else
11
+ effective_posts.post_path(post, opts.merge(category: category))
12
+ end
13
+ end
14
+
4
15
  def render_post(post)
5
16
  render(partial: 'effective/posts/post', locals: { post: post })
6
17
  end
@@ -19,33 +30,37 @@ module EffectivePostsHelper
19
30
  # :omission => '...' passed to the final text node's truncate
20
31
  # :length => 200 to set the max inner_text length of the content
21
32
  # All other options are passed to the link_to 'Read more'
22
- def post_excerpt(post, opts = {})
23
- content = effective_region(post, :content, :editable => false) { '<p>Default content</p>'.html_safe }
24
-
25
- options = {
26
- :label => 'Read more',
27
- :omission => '...',
28
- :length => 200
29
- }.merge(opts)
33
+ def post_excerpt(post, read_more_link: true, label: 'Read more', omission: '...', length: 200)
34
+ content = effective_region(post, :body, :editable => false) { '<p>Default content</p>'.html_safe }
30
35
 
31
36
  divider = content.index(Effective::Snippets::ReadMoreDivider::TOKEN)
32
- length = options.delete(:length)
33
- omission = options.delete(:omission)
37
+ read_more = (read_more_link && label.present?) ? readmore_link(post, label: label) : ''
34
38
 
35
39
  CGI.unescapeHTML(if divider.present?
36
- truncate_html(content, Effective::Snippets::ReadMoreDivider::TOKEN, '') + readmore_link(post, options)
40
+ truncate_html(content, Effective::Snippets::ReadMoreDivider::TOKEN, '') + readmore
37
41
  elsif length.present?
38
- truncate_html(content, length, omission) + readmore_link(post, options)
42
+ truncate_html(content, length, omission) + read_more
39
43
  else
40
44
  content
41
45
  end).html_safe
42
46
  end
43
47
 
44
- def readmore_link(post, options)
48
+ def read_more_link(post, options)
45
49
  content_tag(:p, class: 'post-read-more') do
46
50
  link_to((options.delete(:label) || 'Read more'), effective_posts.post_path(post), options)
47
51
  end
48
52
  end
53
+ alias_method :readmore_link, :read_more_link
54
+
55
+ ### Post Categories
56
+
57
+ def post_categories
58
+ categories = EffectivePosts.categories
59
+ end
60
+
61
+ def render_post_categories
62
+ render(partial: '/effective/posts/categories', locals: { categories: post_categories })
63
+ end
49
64
 
50
65
  def link_to_post_category(category, options = {})
51
66
  category = category.to_s.downcase
@@ -54,9 +69,21 @@ module EffectivePostsHelper
54
69
  link_to(category.to_s.titleize, href, options)
55
70
  end
56
71
 
57
- def effective_post_path(post)
58
- category = post.category.to_s.downcase
59
- EffectivePosts.use_category_routes ? "/#{category}/#{post.to_param}" : effective_posts.post_path(post, category: category.to_s)
72
+ ### Recent Posts
73
+
74
+ def recent_posts(user: current_user, category: nil, limit: EffectivePosts.per_page)
75
+ @recent_posts ||= Effective::Post.posts(user: user, category: category).limit(limit)
76
+ end
77
+
78
+ def render_recent_posts(user: current_user, category: nil, limit: EffectivePosts.per_page)
79
+ posts = recent_posts(user: user, category: category, limit: limit)
80
+
81
+ render partial: '/effective/posts/recent_posts', locals: { posts: posts }
82
+ end
83
+
84
+ ### Submitting a Post
85
+ def link_to_submit_post(label = 'Submit a post', options = {})
86
+ link_to(label, effective_posts.new_post_path, options)
60
87
  end
61
88
 
62
89
  end
@@ -0,0 +1,34 @@
1
+ module Effective
2
+ class PostsMailer < ActionMailer::Base
3
+ helper EffectivePostsHelper
4
+
5
+ layout EffectivePosts.mailer[:layout].presence || 'effective_posts_mailer_layout'
6
+
7
+ def post_submitted_to_admin(post_param)
8
+ @post = (post_param.kind_of?(Effective::Post) ? post_param : Effective::Post.find(post_param))
9
+
10
+ mail(
11
+ to: EffectivePosts.mailer[:admin_email],
12
+ from: EffectivePosts.mailer[:default_from],
13
+ subject: subject_for_post_submitted_to_admin(@post)
14
+ )
15
+ end
16
+
17
+ private
18
+
19
+ def subject_for_post_submitted_to_admin(post)
20
+ string_or_callable = EffectivePosts.mailer[:subject_for_post_submitted_to_admin]
21
+
22
+ if string_or_callable.respond_to?(:call) # This is a Proc or a function, not a string
23
+ string_or_callable = self.instance_exec(post, &string_or_callable)
24
+ end
25
+
26
+ prefix_subject(string_or_callable.presence || "A new post has been submitted that needs approval")
27
+ end
28
+
29
+ def prefix_subject(text)
30
+ prefix = (EffectivePosts.mailer[:subject_prefix].to_s rescue '')
31
+ prefix.present? ? (prefix.chomp(' ') + ' ' + text) : text
32
+ end
33
+ end
34
+ end
@@ -6,14 +6,24 @@ if defined?(EffectiveDatatables)
6
6
  default_order :published_at, :desc
7
7
 
8
8
  table_column :published_at
9
- table_column :id, :visible => false
9
+ table_column :id, visible: false
10
10
 
11
11
  table_column :title
12
- table_column :category, :filter => {:type => :select, :values => EffectivePosts.categories }
12
+ table_column :category, filter: { type: :select, values: EffectivePosts.categories }
13
13
 
14
- table_column :draft
14
+ if EffectivePosts.submissions_enabled
15
+ table_column :approved, column: 'NOT(draft)', as: :boolean do |post|
16
+ post.draft ? 'No' : 'Yes'
17
+ end
15
18
 
16
- table_column :actions, :sortable => false, :filter => false, :partial => '/admin/posts/actions'
19
+ table_column :draft, visible: false
20
+ else
21
+ table_column :draft
22
+ end
23
+
24
+ table_column :created_at, label: 'Submitted at', visible: false
25
+
26
+ table_column :actions, sortable: false, filter: false, partial: '/admin/posts/actions'
17
27
  end
18
28
 
19
29
  def collection
@@ -17,12 +17,48 @@ module Effective
17
17
  # timestamps
18
18
  # end
19
19
 
20
- validates_presence_of :title, :category, :published_at
21
- validates_length_of :title, maximum: 255
20
+ validates :title, presence: true, length: { maximum: 255 }
21
+ validates :category, presence: true
22
+ validates :published_at, presence: true
22
23
 
23
- scope :drafts, -> { where(:draft => true) }
24
- scope :published, -> { where(:draft => false).where("#{EffectivePosts.posts_table_name}.published_at < ?", Time.zone.now) }
25
- scope :with_category, proc { |category| where(:category => category.to_s.downcase) }
24
+ scope :drafts, -> { where(draft: true) }
25
+ scope :published, -> { where(draft: false).where("#{EffectivePosts.posts_table_name}.published_at < ?", Time.zone.now) }
26
+ scope :with_category, -> (category) { where(category: category.to_s.downcase) }
27
+
28
+ scope :posts, -> (user: nil, category: nil, drafts: false) {
29
+ scope = (Rails::VERSION::MAJOR > 3 ? all : scoped)
30
+ scope = scope.includes(:regions).order(published_at: :desc)
31
+
32
+ if user.present? && user.respond_to?(:roles) && defined?(EffectiveRoles)
33
+ scope = scope.for_role(user.roles)
34
+ end
35
+
36
+ if category.present?
37
+ scope = scope.with_category(category)
38
+ end
39
+
40
+ if drafts.blank?
41
+ scope = scope.published
42
+ end
43
+
44
+ scope
45
+ }
46
+
47
+ def to_s
48
+ title.presence || 'New Post'
49
+ end
50
+
51
+ def approved?
52
+ draft == false
53
+ end
54
+
55
+ def body
56
+ region(:body).content
57
+ end
58
+
59
+ def body=(input)
60
+ region(:body).content = input
61
+ end
26
62
 
27
63
  def to_param
28
64
  "#{id}-#{title.parameterize}"
@@ -32,5 +68,27 @@ module Effective
32
68
  def time_to_read_in_seconds(reading_speed = 3.333)
33
69
  (regions.to_a.sum { |region| (region.content || '').scan(/\w+/).size } / reading_speed).seconds
34
70
  end
71
+
72
+ def send_post_submitted_to_admin!
73
+ send_email(:post_submitted_to_admin, to_param)
74
+ end
75
+
76
+ private
77
+
78
+ def send_email(email, *mailer_args)
79
+ begin
80
+ if EffectivePosts.mailer[:delayed_job_deliver] && EffectivePosts.mailer[:deliver_method] == :deliver_later
81
+ Effective::PostsMailer.delay.public_send(email, *mailer_args)
82
+ elsif EffectivePosts.mailer[:deliver_method].present?
83
+ Effective::PostsMailer.public_send(email, *mailer_args).public_send(EffectivePosts.mailer[:deliver_method])
84
+ else
85
+ Effective::PostsMailer.public_send(email, *mailer_args).deliver_now
86
+ end
87
+ rescue => e
88
+ raise e unless Rails.env.production?
89
+ return false
90
+ end
91
+ end
92
+
35
93
  end
36
94
  end
@@ -1,9 +1,16 @@
1
- %span.actions
2
- = link_to 'Visit', effective_post_path(post), :target => '_blank'
3
- = '-'
4
- - if defined?(EffectiveRegions)
5
- = link_to 'Edit Content', '/edit' + effective_posts.post_path(post), 'data-no-turbolink' => true
6
- = '-'
7
- = link_to 'Edit', effective_posts.edit_admin_post_path(post.id)
8
- = '-'
9
- = link_to 'Delete', effective_posts.admin_post_path(post.id), :data => {:method => :delete, :confirm => "Are you sure? This post will be made unavailable."}
1
+ - if EffectivePosts.submissions_enabled && EffectivePosts.submissions_require_approval && !post.approved?
2
+ = link_to effective_posts.admin_approve_post_path(post.id), title: 'Approve' do
3
+ %span.glyphicon.glyphicon-ok
4
+
5
+ = link_to effective_posts.edit_admin_post_path(post.id), title: 'Settings' do
6
+ %span.glyphicon.glyphicon-cog
7
+
8
+ = link_to effective_post_path(post, (post.draft? ? {preview: true} : nil)), title: 'View', target: '_blank' do
9
+ %span.glyphicon.glyphicon-eye-open
10
+
11
+ - if defined?(EffectiveRegions)
12
+ = link_to effective_post_path(post, edit: true), title: 'Edit Content', 'data-no-turbolink': true, target: '_blank' do
13
+ %span.glyphicon.glyphicon-edit
14
+
15
+ = link_to effective_posts.admin_post_path(post.id), title: 'Delete', data: { method: :delete, confirm: 'Are you sure you want to delete? This cannot be undone.' } do
16
+ %span.glyphicon.glyphicon-trash
@@ -1,28 +1,35 @@
1
- = simple_form_for(post, (EffectivePosts.simple_form_options || {}).merge(:url => (post.persisted? ? effective_posts.admin_post_path(post.id) : effective_posts.admin_posts_path))) do |f|
2
- = f.input :title, :hint => "Give this post a title"
1
+ = simple_form_for(post, (EffectivePosts.admin_simple_form_options || {}).merge(:url => (post.persisted? ? effective_posts.admin_post_path(post.id) : effective_posts.admin_posts_path))) do |f|
2
+ = f.input :title, hint: 'The title of your post.'
3
3
 
4
4
  - if Array(EffectivePosts.categories).length > 0
5
- = f.input :category, :collection => EffectivePosts.categories, :as => :select, :include_blank => false
5
+ = f.input :category,
6
+ as: (defined?(EffectiveFormInputs) ? :effective_select : :select),
7
+ collection: EffectivePosts.categories,
8
+ include_blank: false
6
9
  - else
7
- = f.input :category, :as => :hidden, :input_html => {:value => 'posts'}
10
+ = f.input :category, as: :hidden, input_html: { value: 'posts' }
8
11
 
9
- %h4 Publish
10
- = f.input :draft, :hint => "Save this post as a draft. It will not be accessible on the website."
12
+ = render partial: '/effective/posts/additional_fields', locals: { post: post, form: f, f: f }
11
13
 
12
- - if defined?(EffectiveFormInputs)
13
- = f.input :published_at, :as => :effective_date_time_picker, :hint => "Set this to a future date to schedule a post to appear in the future."
14
- - else
15
- = f.input :published_at, :hint => "Set this to a future date to schedule a post to appear in the future."
14
+ = f.input :draft, hint: 'Save this post as a draft. It will not be accessible on the website.'
15
+
16
+ = f.input :published_at,
17
+ as: (defined?(EffectiveFormInputs) ? :effective_date_time_picker : :datetime),
18
+ label: 'Publish date',
19
+ hint: 'When your post will be displayed on the website.'
20
+
21
+ = f.input :body,
22
+ as: (defined?(EffectiveFormInputs) ? :effective_ckeditor_text_area : :text),
23
+ hint: 'The body of your post.',
24
+ toolbar: 'simple',
25
+ required: true
16
26
 
17
- - if defined?(EffectiveRoles) and f.object.respond_to?(:roles)
18
- = f.input :roles, :collection => EffectiveRoles.roles_collection(f.object), :as => :check_boxes, :hint => '* leave blank for a regular public post that anyone can view'
27
+ - if defined?(EffectiveRoles) and f.object.respond_to?(:roles) && EffectivePosts.use_effective_roles
28
+ = f.input :roles, collection: EffectiveRoles.roles_collection(f.object), as: :check_boxes, hint: '* leave blank for a regular public post that anyone can view'
19
29
 
20
- .form-group
21
- .col-xs-12
22
- .form-group
23
- .pull-right
24
- = f.button :submit, 'Save', data: { disable_with: 'Saving...' }
25
- - if defined?(EffectiveRegions)
26
- = f.button :submit, 'Save and Edit Content', data: { disable_with: 'Saving...' }
27
- = f.button :submit, 'Save and Add New', data: { disable_with: 'Saving...' }
28
- = link_to 'Cancel', effective_posts.admin_posts_path
30
+ .effective-post-actions.pull-right
31
+ = f.button :submit, 'Save', data: { disable_with: 'Saving...' }
32
+ - if defined?(EffectiveRegions)
33
+ = f.button :submit, 'Save and Edit Content', data: { disable_with: 'Saving...' }
34
+ = f.button :submit, 'Save and Add New', data: { disable_with: 'Saving...' }
35
+ = link_to 'Cancel', effective_posts.admin_posts_path
@@ -1,2 +1,2 @@
1
1
  %h2= @page_title
2
- = render :partial => 'form', :as => :post, :object => @post
2
+ = render partial: 'form', as: :post, object: @post
@@ -9,7 +9,7 @@
9
9
  = post.title
10
10
  .row
11
11
  .col-sm-6
12
- %pre= effective_region(post, :content, :editable => false)
12
+ %pre= effective_region(post, :body, :editable => false)
13
13
 
14
14
  .col-sm-6
15
15
  %pre= post_excerpt(post)
@@ -1,2 +1,2 @@
1
1
  %h2= @page_title
2
- = render :partial => 'form', :as => :post, :object => @post
2
+ = render partial: 'form', as: :post, object: @post
@@ -0,0 +1,2 @@
1
+ -# intentionally left blank
2
+ -# = form.input :start_at
@@ -0,0 +1,4 @@
1
+ .effective-posts-categories
2
+ - categories.each do |category|
3
+ .effective-post-category
4
+ = link_to_post_category(category)
@@ -0,0 +1,27 @@
1
+ = simple_form_for(post, (EffectivePosts.simple_form_options || {}).merge(:url => (post.persisted? ? effective_posts.post_path(post.id) : effective_posts.posts_path))) do |f|
2
+ = f.input :title, hint: 'The title of your post.'
3
+
4
+ - if Array(EffectivePosts.categories).length > 0
5
+ = f.input :category,
6
+ as: (defined?(EffectiveFormInputs) ? :effective_select : :select),
7
+ collection: EffectivePosts.categories,
8
+ include_blank: false
9
+ - else
10
+ = f.input :category, as: :hidden, input_html: { value: 'posts' }
11
+
12
+ = render partial: '/effective/posts/additional_fields', locals: { post: post, form: f, f: f }
13
+
14
+ = f.input :published_at,
15
+ as: (defined?(EffectiveFormInputs) ? :effective_date_time_picker : :datetime),
16
+ label: 'Publish date',
17
+ hint: 'When your post will be displayed on the website.'
18
+
19
+ = f.input :body,
20
+ as: (defined?(EffectiveFormInputs) ? :effective_ckeditor_text_area : :text),
21
+ hint: 'The body of your post.',
22
+ toolbar: 'simple',
23
+ required: true
24
+
25
+ %p.effective-post-actions.pull-right
26
+ = f.button :submit, 'Save', data: { disable_with: 'Saving...' }
27
+ = link_to 'Cancel', effective_posts.posts_path
@@ -0,0 +1,5 @@
1
+ .effective-posts-recent-posts
2
+ - posts.each do |post|
3
+ .effective-post
4
+ %p= link_to post, effective_post_path(post)
5
+
@@ -0,0 +1 @@
1
+ - # intentionally left blank
@@ -0,0 +1,2 @@
1
+ %h2= @page_title
2
+ = render partial: 'form', as: :post, object: @post
@@ -1,4 +1,9 @@
1
+ - if EffectivePosts.submissions_enabled
2
+ %p.text-right= link_to 'Submit New Post', effective_posts.new_post_path, class: 'btn btn-primary'
3
+
4
+ %nav= paginate @posts
5
+
1
6
  .effective-posts
2
- = render :partial => @posts, :spacer_template => 'spacer'
7
+ = render partial: @posts, spacer_template: 'spacer'
3
8
 
4
- %nav= paginate @posts
9
+ %nav= paginate @posts
@@ -0,0 +1,2 @@
1
+ %h2= @page_title
2
+ = render partial: 'form', as: :post, object: @post
@@ -1,12 +1,12 @@
1
1
  .effective-post
2
2
  %h2.post-title
3
- %a{:href => effective_post_path(@post)}
3
+ %a{href: effective_post_path(@post)}
4
4
  = simple_effective_region @post, :title do
5
5
  = @post.title
6
6
 
7
7
  %p.post-meta= post_meta(@post)
8
8
 
9
- .post-content
10
- = effective_region @post, :content do
9
+ .post-body.post-content
10
+ = effective_region @post, :body do
11
11
  %p Default content
12
12
 
@@ -0,0 +1,10 @@
1
+ %h2= @page_title
2
+
3
+ %p= EffectivePosts.submissions_note
4
+
5
+ - if (EffectivePosts.authorized?(controller, :edit, @post) rescue false)
6
+ %p= link_to 'Edit Post', effective_posts.edit_post_path(@post), class: 'btn btn-primary btn-edit-post'
7
+
8
+ %hr
9
+
10
+ = render file: '/effective/posts/show'
@@ -0,0 +1,22 @@
1
+ %p A new post has been submitted and needs your approval before it may be displayed on the website:
2
+
3
+ %p= link_to 'Approve Post', effective_posts.admin_approve_post_path(@post)
4
+
5
+ %hr
6
+
7
+ %h3 Title
8
+ %p= @post.title
9
+
10
+ %h3 Category
11
+ %p= @post.category
12
+
13
+ - if @post.user.present?
14
+ %h3 Submitted by
15
+ %p= @post.user
16
+
17
+ %h3 Body
18
+ %p= @post.body
19
+
20
+ %hr
21
+
22
+ %p= link_to 'Approve Post', effective_posts.admin_approve_post_path(@post)
@@ -0,0 +1,7 @@
1
+ !!!
2
+ %html{style: 'background: #fff;'}
3
+ %head
4
+ %meta{:content => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type'}
5
+
6
+ %body{style: 'background: #fff;'}
7
+ = yield
data/config/routes.rb CHANGED
@@ -1,18 +1,23 @@
1
1
  EffectivePosts::Engine.routes.draw do
2
2
  namespace :admin do
3
- resources :posts, :except => [:show]
4
- match 'posts/excerpts', :to => 'posts#excerpts', :via => [:get]
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
7
+ end
8
+
9
+ match 'posts/excerpts', to: 'posts#excerpts', via: :get
5
10
  end
6
11
 
7
12
  scope :module => 'effective' do
8
- resources :posts, :only => [:index, :show]
13
+ resources :posts, only: ([:index, :show] unless EffectivePosts.submissions_enabled)
9
14
 
10
15
  if EffectivePosts.use_category_routes
11
- EffectivePosts.categories.each do |category|
12
- next if category.to_s == 'posts'
16
+ Array(EffectivePosts.categories).map { |category| category.to_s }.each do |category|
17
+ next if category == 'posts'
13
18
 
14
- match "#{category}", :to => 'posts#index', :via => [:get], :defaults => {:category => category.to_s }
15
- match "#{category}/:id", :to => 'posts#show', :via => [:get], :defaults => {:category => category.to_s }
19
+ match category, to: 'posts#index', via: :get, defaults: {:category => category }
20
+ match "#{category}/:id", to: 'posts#show', via: :get, defaults: {:category => category }
16
21
  end
17
22
  end
18
23
  end
@@ -10,15 +10,28 @@ module EffectivePosts
10
10
  mattr_accessor :posts_table_name
11
11
 
12
12
  mattr_accessor :authorization_method
13
- mattr_accessor :simple_form_options
13
+ mattr_accessor :permitted_params
14
+
14
15
  mattr_accessor :layout
16
+ mattr_accessor :simple_form_options
17
+ mattr_accessor :admin_simple_form_options
15
18
 
16
19
  mattr_accessor :categories
17
20
  mattr_accessor :use_category_routes
18
21
 
22
+ mattr_accessor :use_effective_roles
23
+
19
24
  mattr_accessor :per_page
20
25
  mattr_accessor :post_meta_author
21
26
 
27
+ mattr_accessor :submissions_enabled
28
+ mattr_accessor :submissions_require_current_user
29
+ mattr_accessor :submissions_require_approval
30
+ mattr_accessor :submissions_note
31
+
32
+ # These are hashes of configs
33
+ mattr_accessor :mailer
34
+
22
35
  def self.setup
23
36
  yield self
24
37
  end
@@ -29,4 +42,9 @@ module EffectivePosts
29
42
  end
30
43
  true
31
44
  end
45
+
46
+ def self.permitted_params
47
+ @@permitted_params ||= [:title, :draft, :category, :published_at, :body, roles: []]
48
+ end
49
+
32
50
  end
@@ -1,3 +1,3 @@
1
1
  module EffectivePosts
2
- VERSION = '0.4.6'.freeze
2
+ VERSION = '0.4.7'.freeze
3
3
  end
@@ -25,6 +25,16 @@ module EffectivePosts
25
25
  migration_template '../../../db/migrate/01_create_effective_posts.rb.erb', 'db/migrate/create_effective_posts.rb'
26
26
  end
27
27
 
28
+ def copy_mailer_preview
29
+ mailer_preview_path = (Rails.application.config.action_mailer.preview_path rescue nil)
30
+
31
+ if mailer_preview_path.present?
32
+ template 'effective_posts_mailer_preview.rb', File.join(mailer_preview_path, 'effective_posts_mailer_preview.rb')
33
+ else
34
+ puts "couldn't find action_mailer.preview_path. Skipping effective_posts_mailer_preview."
35
+ end
36
+ end
37
+
28
38
  def show_readme
29
39
  readme "README" if behavior == :invoke
30
40
  end
@@ -31,22 +31,65 @@ EffectivePosts.setup do |config|
31
31
  # Layout Settings
32
32
  # Configure the Layout per controller, or all at once
33
33
  config.layout = {
34
- :pages => 'application',
35
- :admin => 'application'
34
+ posts: 'application',
35
+ admin: 'application'
36
36
  }
37
37
 
38
38
  # SimpleForm Options
39
- # This Hash of options will be passed into any simple_form_for() calls
39
+ # This Hash of options will be passed into any client facing simple_form_for() calls
40
40
  config.simple_form_options = {}
41
+ config.admin_simple_form_options = {} # For the /admin/posts/new form
41
42
 
42
43
  # config.simple_form_options = {
43
- # :html => {:class => 'form-horizontal'},
44
- # :wrapper => :horizontal_form,
45
- # :wrapper_mappings => {
46
- # :boolean => :horizontal_boolean,
47
- # :check_boxes => :horizontal_radio_and_checkboxes,
48
- # :radio_buttons => :horizontal_radio_and_checkboxes
44
+ # html: {class: 'form-horizontal'},
45
+ # wrapper: :horizontal_form,
46
+ # wrapper_mappings: {
47
+ # boolean: :horizontal_boolean,
48
+ # check_boxes: :horizontal_radio_and_checkboxes,
49
+ # radio_buttons: :horizontal_radio_and_checkboxes
49
50
  # }
50
51
  # }
51
52
 
53
+ # Display the effective roles 'choose roles' input when an admin creates a new post
54
+ config.use_effective_roles = true
55
+
56
+ # Submissions
57
+ # Allow users to submit posts (optionally for approval) to display on the website
58
+ config.submissions_enabled = true
59
+
60
+ # When true, a user might be signed in to submit a post. (calls devise's authenticate_user!)
61
+ config.submissions_require_current_user = false
62
+
63
+ # When true, an Admin must first approve any newly submitted posts before they'll be displayed
64
+ config.submissions_require_approval = true
65
+
66
+ # The Thank you message when they submit a post
67
+ config.submissions_note = "News & Event submitted! A confirmation email has been sent to the AALA office. When approved, your submission will appear on the website."
68
+
69
+ # Mailer Settings
70
+ # effective_posts will send the admin an email when a post is submitted
71
+ # For all the emails, the same :subject_prefix will be prefixed. Leave as nil / empty string if you don't want any prefix
72
+ #
73
+ # The subject_for_post_submitted_to_admin can be one of:
74
+ # - nil / empty string to use the built in defaults
75
+ # - A string with the full subject line for this email
76
+ # - A Proc to create the subject line based on the email
77
+ # In all three of these cases, the subject_prefix will still be used.
78
+
79
+ # The Procs are the same for admin & buyer receipt, the seller Proc is different
80
+ # subject_for_post_submitted_to_admin: Proc.new { |post| "Post needs approval"}
81
+
82
+ config.mailer = {
83
+ subject_prefix: '[example]',
84
+ subject_for_post_submitted_to_admin: '',
85
+
86
+ layout: 'effective_posts_mailer_layout',
87
+
88
+ default_from: 'info@example.com',
89
+ admin_email: 'admin@example.com',
90
+
91
+ deliver_method: nil, # :deliver (rails < 4.2), :deliver_now (rails >= 4.2) or :deliver_later
92
+ delayed_job_deliver: false
93
+ }
94
+
52
95
  end
@@ -0,0 +1,22 @@
1
+ # In Rails 4.1 and above, visit:
2
+ # http://localhost:3000/rails/mailers
3
+ # to see a preview of the following 3 emails:
4
+
5
+ class EffectivePostsMailerPreview < ActionMailer::Preview
6
+ def post_submitted_to_admin
7
+ Effective::PostsMailer.post_submitted_to_admin(build_preview_post)
8
+ end
9
+
10
+ protected
11
+
12
+ def build_preview_post
13
+ post = Effective::Post.new(
14
+ title: 'An example post',
15
+ category: EffectivePosts.categories.first.presence || 'posts',
16
+ published_at: Time.zone.now,
17
+ draft: true,
18
+ content: 'This is a new post that has been submitted by a public user.'
19
+ )
20
+ end
21
+
22
+ end
metadata CHANGED
@@ -1,141 +1,141 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_posts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.6
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-21 00:00:00.000000000 Z
11
+ date: 2016-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 3.2.0
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
26
  version: 3.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: haml-rails
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: sass-rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: kaminari
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: nokogiri
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simple_form
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: effective_ckeditor
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: 1.2.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: 1.2.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: effective_datatables
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '>='
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: 2.0.0
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '>='
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: 2.0.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: effective_regions
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
- version: 1.2.2
131
+ version: 1.6.9
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '>='
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
- version: 1.2.2
138
+ version: 1.6.9
139
139
  description: A blog implementation with WYSIWYG content editing, post scheduling,
140
140
  pagination and optional top level routes for each post category.
141
141
  email:
@@ -155,6 +155,7 @@ files:
155
155
  - app/helpers/effective_kaminari_helper.rb
156
156
  - app/helpers/effective_posts_helper.rb
157
157
  - app/helpers/effective_truncate_html_helper.rb
158
+ - app/mailers/effective/posts_mailer.rb
158
159
  - app/models/effective/access_denied.rb
159
160
  - app/models/effective/datatables/posts.rb
160
161
  - app/models/effective/post.rb
@@ -165,10 +166,18 @@ files:
165
166
  - app/views/admin/posts/excerpts.html.haml
166
167
  - app/views/admin/posts/index.html.haml
167
168
  - app/views/admin/posts/new.html.haml
169
+ - app/views/effective/posts/_additional_fields.html.haml
170
+ - app/views/effective/posts/_categories.html.haml
171
+ - app/views/effective/posts/_form.html.haml
168
172
  - app/views/effective/posts/_post.html.haml
173
+ - app/views/effective/posts/_recent_posts.html.haml
169
174
  - app/views/effective/posts/_spacer.html.haml
175
+ - app/views/effective/posts/edit.html.haml
170
176
  - app/views/effective/posts/index.html.haml
177
+ - app/views/effective/posts/new.html.haml
171
178
  - app/views/effective/posts/show.html.haml
179
+ - app/views/effective/posts/submitted.html.haml
180
+ - app/views/effective/posts_mailer/post_submitted_to_admin.html.haml
172
181
  - app/views/effective/snippets/_read_more_divider.html.haml
173
182
  - app/views/kaminari/_first_page.html.haml
174
183
  - app/views/kaminari/_gap.html.haml
@@ -177,6 +186,7 @@ files:
177
186
  - app/views/kaminari/_page.html.haml
178
187
  - app/views/kaminari/_paginator.html.haml
179
188
  - app/views/kaminari/_prev_page.html.haml
189
+ - app/views/layouts/effective_posts_mailer_layout.html.haml
180
190
  - config/routes.rb
181
191
  - db/migrate/01_create_effective_posts.rb.erb
182
192
  - lib/effective_posts.rb
@@ -185,6 +195,7 @@ files:
185
195
  - lib/generators/effective_posts/install_generator.rb
186
196
  - lib/generators/templates/README
187
197
  - lib/generators/templates/effective_posts.rb
198
+ - lib/generators/templates/effective_posts_mailer_preview.rb
188
199
  - spec/effective_pages_spec.rb
189
200
  - spec/spec_helper.rb
190
201
  - spec/support/factories.rb
@@ -198,17 +209,17 @@ require_paths:
198
209
  - lib
199
210
  required_ruby_version: !ruby/object:Gem::Requirement
200
211
  requirements:
201
- - - '>='
212
+ - - ">="
202
213
  - !ruby/object:Gem::Version
203
214
  version: '0'
204
215
  required_rubygems_version: !ruby/object:Gem::Requirement
205
216
  requirements:
206
- - - '>='
217
+ - - ">="
207
218
  - !ruby/object:Gem::Version
208
219
  version: '0'
209
220
  requirements: []
210
221
  rubyforge_project:
211
- rubygems_version: 2.4.6
222
+ rubygems_version: 2.4.5.1
212
223
  signing_key:
213
224
  specification_version: 4
214
225
  summary: A blog implementation with WYSIWYG content editing, post scheduling, pagination