effective_posts 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +7 -0
  4. data/Rakefile +24 -0
  5. data/app/assets/javascripts/effective/snippets/read_more_divider.js.coffee +22 -0
  6. data/app/assets/javascripts/effective_posts.js +0 -0
  7. data/app/assets/stylesheets/effective_posts.scss +0 -0
  8. data/app/controllers/admin/posts_controller.rb +91 -0
  9. data/app/controllers/effective/posts_controller.rb +51 -0
  10. data/app/helpers/effective_kaminari_helper.rb +16 -0
  11. data/app/helpers/effective_posts_helper.rb +42 -0
  12. data/app/models/effective/access_denied.rb +17 -0
  13. data/app/models/effective/datatables/posts.rb +21 -0
  14. data/app/models/effective/post.rb +39 -0
  15. data/app/models/effective/snippets/read_more_divider.rb +9 -0
  16. data/app/views/admin/posts/_actions.html.haml +9 -0
  17. data/app/views/admin/posts/_form.html.haml +27 -0
  18. data/app/views/admin/posts/edit.html.haml +2 -0
  19. data/app/views/admin/posts/index.html.haml +10 -0
  20. data/app/views/admin/posts/new.html.haml +2 -0
  21. data/app/views/effective/posts/_post.html.haml +9 -0
  22. data/app/views/effective/posts/_spacer.html.haml +0 -0
  23. data/app/views/effective/posts/index.html.haml +4 -0
  24. data/app/views/effective/posts/show.html.haml +12 -0
  25. data/app/views/effective/snippets/_read_more_divider.html.haml +9 -0
  26. data/app/views/kaminari/_first_page.html.haml +2 -0
  27. data/app/views/kaminari/_gap.html.haml +2 -0
  28. data/app/views/kaminari/_last_page.html.haml +2 -0
  29. data/app/views/kaminari/_next_page.html.haml +2 -0
  30. data/app/views/kaminari/_page.html.haml +6 -0
  31. data/app/views/kaminari/_paginator.html.haml +11 -0
  32. data/app/views/kaminari/_prev_page.html.haml +2 -0
  33. data/config/routes.rb +24 -0
  34. data/db/migrate/01_create_effective_posts.rb.erb +26 -0
  35. data/lib/effective_posts.rb +28 -0
  36. data/lib/effective_posts/engine.rb +18 -0
  37. data/lib/effective_posts/version.rb +3 -0
  38. data/lib/generators/effective_posts/install_generator.rb +33 -0
  39. data/lib/generators/templates/README +1 -0
  40. data/lib/generators/templates/effective_posts.rb +53 -0
  41. data/spec/effective_pages_spec.rb +7 -0
  42. data/spec/spec_helper.rb +43 -0
  43. data/spec/support/factories.rb +15 -0
  44. metadata +201 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 100e7584144d920e1e8995378769739f0e384c3c
4
+ data.tar.gz: 7add52b82afb4b69dc3bfd0953e2b0a842b2bacb
5
+ SHA512:
6
+ metadata.gz: 868c82a3b6305bfe6dde3e1d1b98fbfe1384aeadee15ce0c2b5e928e053f0ec61a1fe69f5d55dc1a29ecebe63248325ed44df29d810bcbe89d2c77c38002526f
7
+ data.tar.gz: 30f629262ee514f2ca20fbe46ae628637ee5117278dfc1f11ca024c40ed36f8f406dfe7cd239af424f16e765adf3bfdc4c3652fb1a4d0f42986d4fee9922ab77
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Code and Effect Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # Effective Posts
2
+
3
+ WIP Gem
4
+
5
+ ## TODO
6
+
7
+ Write a README
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ # Our tasks
9
+ load 'lib/tasks/effective_posts_tasks.rake'
10
+
11
+ # Testing tasks
12
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
13
+ load 'rails/tasks/engine.rake'
14
+
15
+ require "bundler/vendored_thor"
16
+ Bundler::GemHelper.install_tasks
17
+
18
+ require 'rspec/core'
19
+ require 'rspec/core/rake_task'
20
+
21
+ desc "Run all specs in spec directory (excluding plugin specs)"
22
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
23
+
24
+ task :default => :spec
@@ -0,0 +1,22 @@
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
+ ]
File without changes
File without changes
@@ -0,0 +1,91 @@
1
+ module Admin
2
+ class PostsController < ApplicationController
3
+ before_filter :authenticate_user! if respond_to?(:authenticate_user!) # This is devise, ensure we're logged in.
4
+
5
+ layout (EffectivePosts.layout.kind_of?(Hash) ? EffectivePosts.layout[:admin] : EffectivePosts.layout)
6
+
7
+ def index
8
+ @page_title = 'Posts'
9
+ EffectivePosts.authorized?(self, :index, Effective::Post)
10
+
11
+ @datatable = Effective::Datatables::Posts.new() if defined?(EffectiveDatatables)
12
+ end
13
+
14
+ def new
15
+ @post = Effective::Post.new(:published_at => Time.zone.now)
16
+ @page_title = 'New Post'
17
+
18
+ EffectivePosts.authorized?(self, :new, @post)
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
+ EffectivePosts.authorized?(self, :create, @post)
28
+
29
+ if @post.save
30
+ if params[:commit] == 'Save and Edit Content' && defined?(EffectiveRegions)
31
+ redirect_to effective_regions.edit_path(effective_posts.post_path(@post), :exit => effective_posts.edit_admin_post_path(@post))
32
+ else
33
+ flash[:success] = 'Successfully created post'
34
+ redirect_to effective_posts.edit_admin_post_path(@post)
35
+ end
36
+ else
37
+ flash.now[:danger] = 'Unable to create post'
38
+ render :action => :new
39
+ end
40
+ end
41
+
42
+ def edit
43
+ @post = Effective::Post.find(params[:id])
44
+ @page_title = 'Edit Post'
45
+
46
+ EffectivePosts.authorized?(self, :edit, @post)
47
+ end
48
+
49
+ def update
50
+ @post = Effective::Post.find(params[:id])
51
+ @page_title = 'Edit Post'
52
+
53
+ EffectivePosts.authorized?(self, :update, @post)
54
+
55
+ if @post.update_attributes(post_params)
56
+ if params[:commit] == 'Save and Edit Content' && defined?(EffectiveRegions)
57
+ redirect_to effective_regions.edit_path(effective_posts.post_path(@post))
58
+ else
59
+ flash[:success] = 'Successfully updated post'
60
+ redirect_to effective_posts.edit_admin_post_path(@post)
61
+ end
62
+ else
63
+ flash.now[:danger] = 'Unable to update post'
64
+ render :action => :edit
65
+ end
66
+ end
67
+
68
+ def destroy
69
+ @post = Effective::Post.find(params[:id])
70
+
71
+ EffectivePosts.authorized?(self, :destroy, @post)
72
+
73
+ if @post.destroy
74
+ flash[:success] = 'Successfully deleted post'
75
+ else
76
+ flash[:danger] = 'Unable to delete post'
77
+ end
78
+
79
+ redirect_to effective_posts.admin_posts_path
80
+ end
81
+
82
+ private
83
+
84
+ def post_params
85
+ params.require(:effective_post).permit(
86
+ :title, :draft, :category, :published_at, :roles => []
87
+ )
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,51 @@
1
+ module Effective
2
+ class PostsController < ApplicationController
3
+ layout (EffectivePosts.layout.kind_of?(Hash) ? EffectivePosts.layout[:posts] : EffectivePosts.layout)
4
+
5
+ after_action :monkey_patch_for_kaminari, :only => [:index]
6
+
7
+ def index
8
+ @posts = (Rails::VERSION::MAJOR > 3 ? Effective::Post.all : Effective::Post.scoped)
9
+
10
+ if defined?(EffectiveRoles) && (current_user.respond_to?(:roles) rescue false)
11
+ @posts = @posts.for_role(current_user.roles)
12
+ end
13
+
14
+ @posts = @posts.includes(:regions)
15
+ @posts = @posts.with_category(params[:category]) if params[:category]
16
+ @posts = @posts.published
17
+
18
+ @posts = @posts.order("#{EffectivePosts.posts_table_name}.published_at DESC")
19
+ @posts = @posts.page(params[:page]).per(EffectivePosts.per_page)
20
+
21
+ EffectivePosts.authorized?(self, :index, Effective::Post)
22
+
23
+ @page_title = (params[:category] || 'Posts').titleize
24
+ end
25
+
26
+ def show
27
+ @posts = (Rails::VERSION::MAJOR > 3 ? Effective::Post.all : Effective::Post.scoped)
28
+
29
+ if defined?(EffectiveRoles) && (current_user.respond_to?(:roles) rescue false)
30
+ @posts = @posts.for_role(current_user.roles)
31
+ end
32
+
33
+ @posts = @posts.includes(:regions)
34
+ @posts = @posts.with_category(params[:category]) if params[:category]
35
+ @posts = @posts.published if params[:edit].to_s != 'true'
36
+
37
+ @post = @posts.find(params[:id])
38
+
39
+ EffectivePosts.authorized?(self, :show, @post)
40
+
41
+ @page_title = @post.title
42
+ end
43
+
44
+ private
45
+
46
+ def monkey_patch_for_kaminari
47
+ @template = @template.tap { |template| template.extend(EffectiveKaminariHelper) }
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,16 @@
1
+ # This extends the @template.url_for method to work with Kaminari
2
+ # It is only extended on the posts#index method, for minimal pollution
3
+
4
+ module EffectiveKaminariHelper
5
+ def url_for(params)
6
+ if params.kind_of?(Hash) && params[:controller] == 'effective/posts' && params[:action] == 'index'
7
+ params.delete(:page) if params[:page].blank?
8
+ params.delete(:category) if EffectivePosts.use_category_routes
9
+ params = params.except(:action, :controller, :only_path)
10
+
11
+ request.path.to_s + (params.present? ? '?' : '') + params.to_param
12
+ else
13
+ super
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,42 @@
1
+ module EffectivePostsHelper
2
+ def render_post(post)
3
+ render(:partial => 'effective/posts/post', :locals => {:post => post})
4
+ end
5
+
6
+ def post_meta(post)
7
+ [
8
+ "Published",
9
+ "on #{post.published_at.strftime("%d-%b-%Y %l:%M %p")}",
10
+ ("to #{link_to_post_category(post.category)}" if Array(EffectivePosts.categories).length > 0),
11
+ ("by #{post.user.to_s.presence || 'Unknown'}" if EffectivePosts.post_meta_author)
12
+ ].compact.join(' ').html_safe
13
+ end
14
+
15
+ def post_excerpt(post, options = {})
16
+ content = effective_region(post, :content) { "<p>Default content</p>".html_safe }
17
+
18
+ index = content.index(Effective::Snippets::ReadMoreDivider::TOKEN)
19
+
20
+ if index.present? # We have to return the excerpt and add a Read more... link
21
+ content[0...index].html_safe +
22
+ content_tag(:p, :class => 'post-read-more') do
23
+ link_to((options.delete(:label) || 'Read more...'), effective_post_path(post), options)
24
+ end
25
+ else
26
+ content
27
+ end
28
+ end
29
+
30
+ def link_to_post_category(category, options = {})
31
+ category = category.to_s.downcase
32
+
33
+ href = EffectivePosts.use_category_routes ? "/#{category}" : effective_posts.posts_path(:category => category.to_s)
34
+ link_to(category.to_s.titleize, href, options)
35
+ end
36
+
37
+ def effective_post_path(post)
38
+ category = post.category.to_s.downcase
39
+ EffectivePosts.use_category_routes ? "/#{category}/#{post.to_param}" : effective_posts.post_path(post, :category => category.to_s)
40
+ end
41
+
42
+ end
@@ -0,0 +1,17 @@
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
@@ -0,0 +1,21 @@
1
+ if defined?(EffectiveDatatables)
2
+ module Effective
3
+ module Datatables
4
+ class Posts < Effective::Datatable
5
+ table_column :id
6
+
7
+ table_column :title
8
+ table_column :category, :filter => {:type => :select, :values => EffectivePosts.categories }
9
+
10
+ table_column :draft
11
+ table_column :published_at
12
+
13
+ table_column :actions, :sortable => false, :filter => false, :partial => '/admin/posts/actions'
14
+
15
+ def collection
16
+ Effective::Post.all
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ module Effective
2
+ class Post < ActiveRecord::Base
3
+ acts_as_role_restricted if defined?(EffectiveRoles)
4
+ acts_as_regionable if defined?(EffectiveRegions)
5
+
6
+ self.table_name = EffectivePosts.posts_table_name.to_s
7
+
8
+ belongs_to :user
9
+
10
+ structure do
11
+ title :string, :validates => [:presence]
12
+ category :string, :validates => [:presence]
13
+
14
+ published_at :datetime, :validates => [:presence]
15
+
16
+ draft :boolean, :default => false
17
+
18
+ tags :text
19
+
20
+ roles_mask :integer, :default => 0
21
+
22
+ timestamps
23
+ end
24
+
25
+ scope :drafts, -> { where(:draft => true) }
26
+ scope :published, -> { where(:draft => false).where("#{EffectivePosts.posts_table_name}.published_at < ?", Time.zone.now) }
27
+ scope :with_category, proc { |category| where(:category => category.to_s.downcase) }
28
+
29
+ def to_param
30
+ "#{id}-#{title.parameterize}"
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+
38
+
39
+
@@ -0,0 +1,9 @@
1
+ module Effective
2
+ module Snippets
3
+ class ReadMoreDivider < Snippet
4
+ TOKEN = "<div style='display: none;'>READ_MORE_DIVIDER</div>"
5
+
6
+ attribute :throwaway, String
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
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."}
@@ -0,0 +1,27 @@
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"
3
+
4
+ - if Array(EffectivePosts.categories).length > 0
5
+ = f.input :category, :collection => EffectivePosts.categories, :as => :select, :include_blank => false
6
+ - else
7
+ = f.input :category, :as => :hidden, :input_html => {:value => 'posts'}
8
+
9
+ %h4 Publish
10
+ = f.input :draft, :hint => "Save this post as a draft. It will not be accessible on the website."
11
+
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."
16
+
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'
19
+
20
+ .form-group
21
+ .col-xs-12
22
+ .form-group
23
+ .pull-right
24
+ = f.button :submit, 'Save'
25
+ - if defined?(EffectiveRegions)
26
+ = f.button :submit, 'Save and Edit Content'
27
+ = link_to 'Cancel', effective_posts.admin_posts_path
@@ -0,0 +1,2 @@
1
+ %h2= @page_title
2
+ = render :partial => 'form', :as => :post, :object => @post
@@ -0,0 +1,10 @@
1
+ %h2= @page_title
2
+
3
+ - if @datatable.nil?
4
+ %p Please install #{link_to 'effective_datatables', 'https://github.com/code-and-effect/effective_datatables'} to view this page
5
+ - elsif @datatable.collection.length == 0
6
+ %p There are no posts
7
+ - else
8
+ = render_datatable @datatable
9
+
10
+ %p= link_to 'New Post', effective_posts.new_admin_post_path, :class => 'btn btn-primary'
@@ -0,0 +1,2 @@
1
+ %h2= @page_title
2
+ = render :partial => 'form', :as => :post, :object => @post
@@ -0,0 +1,9 @@
1
+ .effective-post
2
+ %h2.post-title
3
+ %a{:href => effective_post_path(post)}
4
+ = simple_effective_region post, :title do
5
+ = post.title
6
+
7
+ %p.post-meta= post_meta(post)
8
+
9
+ .post-content.post-excerpt= post_excerpt(post)
File without changes
@@ -0,0 +1,4 @@
1
+ .effective-posts
2
+ = render :partial => @posts, :spacer_template => 'spacer'
3
+
4
+ %nav= paginate @posts
@@ -0,0 +1,12 @@
1
+ .effective-post
2
+ %h2.post-title
3
+ %a{:href => effective_post_path(@post)}
4
+ = simple_effective_region @post, :title do
5
+ = @post.title
6
+
7
+ %p.post-meta= post_meta(@post)
8
+
9
+ .post-content
10
+ = effective_region @post, :content do
11
+ %p Default content
12
+
@@ -0,0 +1,9 @@
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
+
@@ -0,0 +1,2 @@
1
+ %li
2
+ = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote
@@ -0,0 +1,2 @@
1
+ %li.disabled
2
+ = content_tag :a, raw(t 'views.pagination.truncate')
@@ -0,0 +1,2 @@
1
+ %li
2
+ = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote}
@@ -0,0 +1,2 @@
1
+ %li
2
+ = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote
@@ -0,0 +1,6 @@
1
+ - if page.current?
2
+ %li.active
3
+ = content_tag :a, page, remote: remote, rel: (page.next? ? 'next' : (page.prev? ? 'prev' : nil))
4
+ - else
5
+ %li
6
+ = link_to page, url, remote: remote, rel: (page.next? ? 'next' : (page.prev? ? 'prev' : nil))
@@ -0,0 +1,11 @@
1
+ = paginator.render do
2
+ %ul.pagination
3
+ = first_page_tag unless current_page.first?
4
+ = prev_page_tag unless current_page.first?
5
+ - each_page do |page|
6
+ - if page.left_outer? || page.right_outer? || page.inside_window?
7
+ = page_tag page
8
+ - elsif !page.was_truncated?
9
+ = gap_tag
10
+ = next_page_tag unless current_page.last?
11
+ = last_page_tag unless current_page.last?
@@ -0,0 +1,2 @@
1
+ %li
2
+ = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote
data/config/routes.rb ADDED
@@ -0,0 +1,24 @@
1
+ EffectivePosts::Engine.routes.draw do
2
+ namespace :admin do
3
+ resources :posts, :except => [:show]
4
+ end
5
+
6
+ scope :module => 'effective' do
7
+ resources :posts, :only => [:index, :show]
8
+
9
+ if EffectivePosts.use_category_routes
10
+ EffectivePosts.categories.each do |category|
11
+ match "#{category}", :to => 'posts#index', :via => [:get], :defaults => {:category => category.to_s }
12
+ match "#{category}/:id", :to => 'posts#show', :via => [:get], :defaults => {:category => category.to_s }
13
+ end
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ # Automatically mount the engine as an append
20
+ Rails.application.routes.append do
21
+ unless Rails.application.routes.routes.find { |r| r.name == 'effective_posts' }
22
+ mount EffectivePosts::Engine => '/', :as => 'effective_posts'
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ class CreateEffectivePosts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table <%= @posts_table_name %> do |t|
4
+ t.integer :user_id
5
+
6
+ t.string :title
7
+ t.string :category
8
+
9
+ t.boolean :draft, :default => false
10
+
11
+ t.text :tags
12
+
13
+ t.integer :roles_mask, :default => 0
14
+
15
+ t.datetime :published_at
16
+
17
+ t.datetime :updated_at
18
+ t.datetime :created_at
19
+ end
20
+ end
21
+
22
+ def self.down
23
+ drop_table <%= @posts_table_name %>
24
+ end
25
+
26
+ end
@@ -0,0 +1,28 @@
1
+ require 'kaminari'
2
+ require 'migrant' # Required for rspec to run properly
3
+ require "effective_posts/engine"
4
+
5
+ module EffectivePosts
6
+ mattr_accessor :posts_table_name
7
+
8
+ mattr_accessor :authorization_method
9
+ mattr_accessor :simple_form_options
10
+ mattr_accessor :layout
11
+
12
+ mattr_accessor :categories
13
+ mattr_accessor :use_category_routes
14
+
15
+ mattr_accessor :per_page
16
+ mattr_accessor :post_meta_author
17
+
18
+ def self.setup
19
+ yield self
20
+ end
21
+
22
+ def self.authorized?(controller, action, resource)
23
+ if authorization_method.respond_to?(:call) || authorization_method.kind_of?(Symbol)
24
+ raise Effective::AccessDenied.new() unless (controller || self).instance_exec(controller, action, resource, &authorization_method)
25
+ end
26
+ true
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module EffectivePosts
2
+ class Engine < ::Rails::Engine
3
+ engine_name 'effective_posts'
4
+
5
+ # Include Helpers to base application
6
+ initializer 'effective_posts.action_controller' do |app|
7
+ ActiveSupport.on_load :action_controller do
8
+ helper EffectivePostsHelper
9
+ end
10
+ end
11
+
12
+ # Set up our default configuration options.
13
+ initializer "effective_posts.defaults", :before => :load_config_initializers do |app|
14
+ # Set up our defaults, as per our initializer template
15
+ eval File.read("#{config.root}/lib/generators/templates/effective_posts.rb")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module EffectivePosts
2
+ VERSION = "0.1"
3
+ end
@@ -0,0 +1,33 @@
1
+ module EffectivePosts
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+
6
+ desc "Creates an EffectivePosts initializer in your application."
7
+
8
+ source_root File.expand_path("../../templates", __FILE__)
9
+
10
+ def self.next_migration_number(dirname)
11
+ if not ActiveRecord::Base.timestamped_migrations
12
+ Time.new.utc.strftime("%Y%m%d%H%M%S")
13
+ else
14
+ "%.3d" % (current_migration_number(dirname) + 1)
15
+ end
16
+ end
17
+
18
+ def copy_initializer
19
+ template "effective_posts.rb", "config/initializers/effective_posts.rb"
20
+ end
21
+
22
+ def create_migration_file
23
+ @posts_table_name = ':' + EffectivePosts.posts_table_name.to_s
24
+
25
+ migration_template '../../../db/migrate/01_create_effective_posts.rb.erb', 'db/migrate/create_effective_posts.rb'
26
+ end
27
+
28
+ def show_readme
29
+ readme "README" if behavior == :invoke
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1 @@
1
+ Thanks for using EffectivePosts
@@ -0,0 +1,53 @@
1
+ # EffectivePosts Rails Engine
2
+
3
+ EffectivePosts.setup do |config|
4
+ config.posts_table_name = :posts
5
+
6
+ # Every post must belong to one or more category
7
+ # Only add to the end of this array. Never prepend categories.
8
+ # Don't include :posts
9
+ config.categories = [:blog, :news]
10
+
11
+ # Create top level routes for each category
12
+ # Should each of the above categories have a top level route created for it
13
+ # For example:
14
+ # Visiting /blog will display all posts created with the :blog category
15
+ # Visiting /news will display all posts created with the :news category
16
+ #
17
+ # Regardless of this setting, posts will always be available via /posts?category=blog
18
+ config.use_category_routes = true
19
+
20
+ # Number of posts displayed per page (Kaminari)
21
+ config.per_page = 10
22
+
23
+ # Post Meta behaviour
24
+ # Should the author be displayed in the post meta?
25
+ # The author is the user that created the Effective::Post object
26
+ config.post_meta_author = true
27
+
28
+ # Use CanCan: authorize!(action, resource)
29
+ # Use effective_roles: resource.roles_match_with?(current_user)
30
+ config.authorization_method = Proc.new { |controller, action, resource| true }
31
+
32
+ # Layout Settings
33
+ # Configure the Layout per controller, or all at once
34
+ config.layout = {
35
+ :pages => 'application',
36
+ :admin => 'application'
37
+ }
38
+
39
+ # SimpleForm Options
40
+ # This Hash of options will be passed into any simple_form_for() calls
41
+ config.simple_form_options = {}
42
+
43
+ # config.simple_form_options = {
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
50
+ # }
51
+ # }
52
+
53
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe EffectivePosts do
4
+ it 'should be a module' do
5
+ assert_kind_of Module, EffectivePosts
6
+ end
7
+ end
@@ -0,0 +1,43 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+
3
+ require File.expand_path("../dummy/config/environment", __FILE__)
4
+
5
+ require 'rspec/rails'
6
+ require 'rspec/autorun'
7
+ require 'capybara/rspec'
8
+ require 'capybara/poltergeist'
9
+ require 'factory_girl_rails'
10
+ require 'haml'
11
+
12
+ # Requires supporting ruby files with custom matchers and macros, etc,
13
+ # in spec/support/ and its subdirectories.
14
+ Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f }
15
+
16
+ RSpec.configure do |config|
17
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
18
+
19
+ config.include Capybara::DSL
20
+
21
+ Capybara.current_driver = :poltergeist
22
+ Capybara.javascript_driver = :poltergeist
23
+ Capybara.default_wait_time = 5
24
+
25
+ Rails.logger.level = 4 # Output only minimal stuff to test.log
26
+
27
+ config.use_transactional_fixtures = true # Make this false to once again use DatabaseCleaner
28
+ config.infer_base_class_for_anonymous_controllers = false
29
+ config.order = 'random'
30
+ end
31
+
32
+ class ActiveRecord::Base
33
+ mattr_accessor :shared_connection
34
+ @@shared_connection = nil
35
+
36
+ def self.connection
37
+ @@shared_connection || retrieve_connection
38
+ end
39
+ end
40
+
41
+ # Forces all threads to share the same connection. This works on
42
+ # Capybara because it starts the web server in a thread.
43
+ ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
@@ -0,0 +1,15 @@
1
+ require 'factory_girl'
2
+
3
+ FactoryGirl.define do
4
+ factory :post, :class => Effective::Post do
5
+ sequence(:title) { |n| "Title #{n}" }
6
+ sequence(:slug) { |n| "title-#{n}" }
7
+
8
+ meta_description 'meta description'
9
+ draft false
10
+
11
+ template 'example'
12
+ layout 'application'
13
+ end
14
+ end
15
+
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: effective_posts
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Code and Effect
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: haml
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sass-rails
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
+ - !ruby/object:Gem::Dependency
56
+ name: kaminari
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: migrant
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simple_form
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: effective_ckeditor
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.1.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 1.1.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: effective_regions
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 1.2.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 1.2.0
125
+ description: CRUD Posts with intention to work with EffectiveRegions. WIP.
126
+ email:
127
+ - info@codeandeffect.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - MIT-LICENSE
133
+ - README.md
134
+ - Rakefile
135
+ - app/assets/javascripts/effective/snippets/read_more_divider.js.coffee
136
+ - app/assets/javascripts/effective_posts.js
137
+ - app/assets/stylesheets/effective_posts.scss
138
+ - app/controllers/admin/posts_controller.rb
139
+ - app/controllers/effective/posts_controller.rb
140
+ - app/helpers/effective_kaminari_helper.rb
141
+ - app/helpers/effective_posts_helper.rb
142
+ - app/models/effective/access_denied.rb
143
+ - app/models/effective/datatables/posts.rb
144
+ - app/models/effective/post.rb
145
+ - app/models/effective/snippets/read_more_divider.rb
146
+ - app/views/admin/posts/_actions.html.haml
147
+ - app/views/admin/posts/_form.html.haml
148
+ - app/views/admin/posts/edit.html.haml
149
+ - app/views/admin/posts/index.html.haml
150
+ - app/views/admin/posts/new.html.haml
151
+ - app/views/effective/posts/_post.html.haml
152
+ - app/views/effective/posts/_spacer.html.haml
153
+ - app/views/effective/posts/index.html.haml
154
+ - app/views/effective/posts/show.html.haml
155
+ - app/views/effective/snippets/_read_more_divider.html.haml
156
+ - app/views/kaminari/_first_page.html.haml
157
+ - app/views/kaminari/_gap.html.haml
158
+ - app/views/kaminari/_last_page.html.haml
159
+ - app/views/kaminari/_next_page.html.haml
160
+ - app/views/kaminari/_page.html.haml
161
+ - app/views/kaminari/_paginator.html.haml
162
+ - app/views/kaminari/_prev_page.html.haml
163
+ - config/routes.rb
164
+ - db/migrate/01_create_effective_posts.rb.erb
165
+ - lib/effective_posts.rb
166
+ - lib/effective_posts/engine.rb
167
+ - lib/effective_posts/version.rb
168
+ - lib/generators/effective_posts/install_generator.rb
169
+ - lib/generators/templates/README
170
+ - lib/generators/templates/effective_posts.rb
171
+ - spec/effective_pages_spec.rb
172
+ - spec/spec_helper.rb
173
+ - spec/support/factories.rb
174
+ homepage: https://github.com/code-and-effect/effective_posts
175
+ licenses:
176
+ - MIT
177
+ metadata: {}
178
+ post_install_message:
179
+ rdoc_options: []
180
+ require_paths:
181
+ - lib
182
+ required_ruby_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ required_rubygems_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubyforge_project:
194
+ rubygems_version: 2.4.3
195
+ signing_key:
196
+ specification_version: 4
197
+ summary: CRUD Posts with intention to work with EffectiveRegions. WIP.
198
+ test_files:
199
+ - spec/effective_pages_spec.rb
200
+ - spec/spec_helper.rb
201
+ - spec/support/factories.rb