wa_bcms_blog 1.1.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.
Files changed (51) hide show
  1. data/LICENSE.txt +165 -0
  2. data/README.markdown +101 -0
  3. data/app/controllers/application_controller.rb +10 -0
  4. data/app/controllers/cms/blog_comments_controller.rb +3 -0
  5. data/app/controllers/cms/blog_posts_controller.rb +35 -0
  6. data/app/controllers/cms/blogs_controller.rb +11 -0
  7. data/app/helpers/application_helper.rb +3 -0
  8. data/app/helpers/cms/blog_helper.rb +11 -0
  9. data/app/models/blog.rb +162 -0
  10. data/app/models/blog_comment.rb +32 -0
  11. data/app/models/blog_group_membership.rb +4 -0
  12. data/app/models/blog_post.rb +113 -0
  13. data/app/portlets/blog_post_portlet.rb +38 -0
  14. data/app/portlets/blog_posts_portlet.rb +50 -0
  15. data/app/views/cms/blog_comments/_form.html.erb +5 -0
  16. data/app/views/cms/blog_comments/render.html.erb +2 -0
  17. data/app/views/cms/blog_posts/_form.html.erb +11 -0
  18. data/app/views/cms/blog_posts/no_access.html.erb +9 -0
  19. data/app/views/cms/blog_posts/render.html.erb +1 -0
  20. data/app/views/cms/blogs/_form.html.erb +28 -0
  21. data/app/views/cms/blogs/admin_only.html.erb +9 -0
  22. data/app/views/cms/blogs/render.html.erb +2 -0
  23. data/app/views/partials/_blog_post.html.erb +103 -0
  24. data/app/views/partials/_blog_post.html.haml +91 -0
  25. data/app/views/portlets/blog_post/_form.html.erb +3 -0
  26. data/app/views/portlets/blog_post/render.html.erb +33 -0
  27. data/app/views/portlets/blog_posts/_form.html.erb +13 -0
  28. data/app/views/portlets/blog_posts/render.html.haml +9 -0
  29. data/db/migrate/20090415000000_create_blogs.rb +45 -0
  30. data/db/migrate/20090415000001_create_blog_posts.rb +25 -0
  31. data/db/migrate/20090415000002_create_blog_comments.rb +19 -0
  32. data/db/migrate/20090415000003_add_attachment_to_blog_posts.rb +23 -0
  33. data/db/migrate/20100521042244_add_moderate_comments_to_blog.rb +10 -0
  34. data/doc/README_FOR_APP +2 -0
  35. data/doc/migrate_to_20100427.rb +77 -0
  36. data/doc/release_notes.txt +40 -0
  37. data/lib/bcms_blog.rb +1 -0
  38. data/lib/bcms_blog/routes.rb +9 -0
  39. data/rails/init.rb +4 -0
  40. data/test/factories.rb +48 -0
  41. data/test/functional/blog_post_test.rb +42 -0
  42. data/test/functional/blog_test.rb +74 -0
  43. data/test/functional/cms/blog_posts_controller_test.rb +46 -0
  44. data/test/functional/cms/blogs_controller_test.rb +25 -0
  45. data/test/performance/browsing_test.rb +9 -0
  46. data/test/test_helper.rb +103 -0
  47. data/test/test_logging.rb +64 -0
  48. data/test/unit/blog_comment_test.rb +34 -0
  49. data/test/unit/blog_post_test.rb +43 -0
  50. data/test/unit/blog_test.rb +86 -0
  51. metadata +127 -0
@@ -0,0 +1,3 @@
1
+ <%= f.cms_text_field :name %>
2
+ <%= f.cms_drop_down :blog_id, Blog.all.map{|b| [b.name, b.id.to_s]} %>
3
+ <%# f.cms_text_area :template, :default_value => @block.class.default_template %>
@@ -0,0 +1,33 @@
1
+ <% page_title @blog_post.name %>
2
+ <%= render :partial => "partials/blog_post", :object => @blog_post %>
3
+
4
+ <style>
5
+ @import url('/stylesheets/cms/form_layout.css');
6
+ </style>
7
+
8
+ <div class="blog_comment_form">
9
+ <% form_for @blog_comment, :url => cms_handler_path(@portlet, "create_comment") do |f| %>
10
+ <%= f.hidden_field :post_id %>
11
+ <%= f.error_messages %>
12
+ <div class="fields text_fields">
13
+ <%= f.label :author, 'Name *' %>
14
+ <%= f.text_field :author %>
15
+ </div>
16
+ <div class="fields text_fields clear">
17
+ <%= f.label :email, 'E-mail address' %>
18
+ <%= f.text_field :email %>
19
+ </div>
20
+ <div class="fields text_fields clear">
21
+ <%= f.label :url, 'Web site' %>
22
+ <%= f.text_field :url %>
23
+ </div>
24
+ <div class="fields text_editor_fields clear">
25
+ <%= f.label :body, 'Body *' %>
26
+ <br/>
27
+ <%= f.text_area :body, :size => "50x5", :style => 'height: auto' %>
28
+ </div>
29
+ <div class="buttons clear">
30
+ <%= submit_tag "Submit comment" %>
31
+ </div>
32
+ <% end %>
33
+ </div>
@@ -0,0 +1,13 @@
1
+ <%= f.cms_text_field :name, :label => 'Portlet Name', :instructions => 'Since we may have many Articles portlets, each with different parameters, give each portlet a descriptive name.' %>
2
+
3
+ <%= f.cms_drop_down :blog_id, Blog.all.map{|b| [b.name, b.id.to_s]}, :include_blank => true, :label => "Show posts from", :instructions => 'Leave blank to include posts from all blogs' %>
4
+ <%# f.cms_drop_down :show_posts_as, [['First post as full post, the rest as Summary + Read More link', 'first_full_post_others_summary'], ['Summary + Read More link', 'summary'], ['Full post', 'full_post'], ['Title (links to post)', 'link']] %>
5
+ <%= f.cms_drop_down :show_posts_as, [['Title (links to post)', 'link'], ['Post', 'post']] %>
6
+ <%= f.cms_check_box :show_full_posts %>
7
+ <%= f.cms_drop_down :category_id, categories_for('Blog Post').map{|c| [c.path, c.id]}, :include_blank => true, :label => "Only posts in category" %>
8
+ <%= f.cms_tag_list :label => "Only posts with tags", :instructions => 'Separate tags with spaces' %>
9
+ <%= f.cms_text_field :exclude_tags, :label => 'Exclude posts with tags' %>
10
+ <%= f.cms_text_field :limit, :label => 'Limit' %>
11
+ <%= f.cms_text_area :render_blog_post_code, :label => 'Code to turn blog_post into link text' %>
12
+
13
+ <%= f.cms_template_editor :template %>
@@ -0,0 +1,9 @@
1
+ - if @portlet.show_posts_as == 'post'
2
+ = render :partial => '/partials/blog_post', :collection => @blog_posts, :locals => {:show_full_posts => @options[:show_full_posts]}
3
+ - elsif @portlet.show_posts_as == 'link'
4
+ %ul.blog_posts
5
+ - for blog_post in @blog_posts
6
+ - text = @portlet.render_blog_post_code.present? ? eval(@portlet.render_blog_post_code) : text = truncate(blog_post.name, 30)
7
+ %li= link_to text, _blog_post_path(blog_post)
8
+ - else
9
+ Unrecognized option '#{@portlet.show_posts_as}' for @portlet.show_posts_as
@@ -0,0 +1,45 @@
1
+ require 'pp'
2
+
3
+ Page # trigger auto-loading
4
+ # At the time of this writing, these associations are missing :dependent => :destroy
5
+ class Page
6
+ has_many :page_routes, :dependent => :destroy
7
+ end
8
+ class PageRoute
9
+ has_many :requirements, :class_name => "PageRouteRequirement", :dependent => :destroy
10
+ has_many :conditions, :class_name => "PageRouteCondition", :dependent => :destroy
11
+ end
12
+
13
+ class CreateBlogs < ActiveRecord::Migration
14
+ def self.up
15
+ create_versioned_table :blogs do |t|
16
+ t.string :name
17
+ t.string :format
18
+ t.text :template
19
+ end
20
+
21
+ create_table :blog_group_memberships do |t|
22
+ t.integer :blog_id
23
+ t.integer :group_id
24
+ end
25
+
26
+ ContentType.create!(:name => "Blog", :group_name => "Blog")
27
+ end
28
+
29
+ def self.down
30
+ puts "Destroying portlets, pages, page_routes..."
31
+ pp (portlets = BlogPostPortlet.all).map(&:connected_pages).flatten.each(&:destroy)
32
+ pp portlets.each(&:destroy)
33
+
34
+ #Blog.all.map(&:connected_pages).flatten.map(&:page_routes).flatten.each(&:destroy)
35
+ pp Blog.all.map(&:connected_pages).flatten.each(&:destroy)
36
+
37
+ ContentType.destroy_all(:name => "Blog")
38
+ Connector.destroy_all(:connectable_type => "Blog")
39
+
40
+ drop_table :blog_versions
41
+ drop_table :blogs
42
+
43
+ drop_table :blog_group_memberships
44
+ end
45
+ end
@@ -0,0 +1,25 @@
1
+ class CreateBlogPosts < ActiveRecord::Migration
2
+ def self.up
3
+ create_versioned_table :blog_posts do |t|
4
+ t.integer :blog_id
5
+ t.integer :author_id
6
+ t.integer :category_id
7
+ t.string :name
8
+ t.string :slug
9
+ t.text :summary
10
+ t.text :body, :size => (64.kilobytes + 1)
11
+ t.integer :comments_count
12
+ t.datetime :published_at
13
+ end
14
+ CategoryType.create!(:name => "Blog Post")
15
+ ContentType.create!(:name => "BlogPost", :group_name => "Blog")
16
+ end
17
+
18
+ def self.down
19
+ ContentType.destroy_all(:name => 'BlogPost')
20
+ CategoryType.destroy_all(:name => "Blog Post")
21
+
22
+ drop_table :blog_post_versions
23
+ drop_table :blog_posts
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ class CreateBlogComments < ActiveRecord::Migration
2
+ def self.up
3
+ create_versioned_table :blog_comments do |t|
4
+ t.integer :post_id
5
+ t.string :author
6
+ t.string :email
7
+ t.string :url
8
+ t.string :ip
9
+ t.text :body
10
+ end
11
+ ContentType.create!(:name => "BlogComment", :group_name => "Blog")
12
+ end
13
+
14
+ def self.down
15
+ ContentType.destroy_all(:name => 'BlogComment')
16
+ drop_table :blog_comment_versions
17
+ drop_table :blog_comments
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ class AddAttachmentToBlogPosts < ActiveRecord::Migration
2
+ def self.up
3
+ change_table :blog_posts do |t|
4
+ t.belongs_to :attachment
5
+ t.integer :attachment_version
6
+ end
7
+ change_table :blog_post_versions do |t|
8
+ t.belongs_to :attachment
9
+ t.integer :attachment_version
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ change_table :blog_posts do |t|
15
+ t.remove :attachment
16
+ t.remove :attachment_version
17
+ end
18
+ change_table :blog_post_versions do |t|
19
+ t.remove :attachment
20
+ t.remove :attachment_version
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ class AddModerateCommentsToBlog < ActiveRecord::Migration
2
+ def self.up
3
+ add_content_column :blogs, :moderate_comments, :boolean, :default => true
4
+ end
5
+
6
+ def self.down
7
+ remove_column :blogs, :moderate_comments
8
+ remove_column :blog_versions, :moderate_comments
9
+ end
10
+ end
@@ -0,0 +1,2 @@
1
+ Use this README file to introduce your application and point to useful places in the API for learning more.
2
+ Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
@@ -0,0 +1,77 @@
1
+ # Ideally, we would create a new migration whenever we wanted to make changes to an existing
2
+ # migration that is already in circulation, instead of simply editing the existing migrations
3
+ # and publishing the new version, because doing rake db:migrate:redo VERSION=20090415000000,
4
+ # etc. on each updated migration is not only a pain but will probably result in more data being
5
+ # lost than is strictly necessary -- assuming the migrations work correctly at all.
6
+ #
7
+ # On the other hand, there's something pretty compelling about "fixing" the migration so that
8
+ # it doesn't have any useless steps that are just going to get reverted by the next migration.
9
+ #
10
+ # There is also the problem of model dependencies: you can't safely remove a model in the same
11
+ # commit that you use that model in a migration (f.e., Model.destroy_all). Even if you remove it
12
+ # in the following commit, it's only safe if people check out every intermediate version and run
13
+ # db:migrate at each version, instead of simply checking out the tip version and then running
14
+ # db:migrate. And people don't do that.
15
+ #
16
+ # Anyway, I guess we assume that there are only a few brave souls out there who are already
17
+ # using bcms_blog and hope for the best. Here is the "missing migration"; hopefully it will be
18
+ # helpful to you.
19
+ #
20
+ # Run this script instead of re-running the changed migrations with rake db:migrate:redo so that
21
+ # your blog data is not destroyed.
22
+ #
23
+ # Usage: ./script/runner 'require "/path/to/bcms_blog/doc/migrate_to_20100427.rb"'
24
+
25
+ require 'pp'
26
+
27
+ Page # trigger auto-loading
28
+ # At the time of this writing, these associations are missing :dependent => :destroy
29
+ class Page
30
+ has_many :page_routes, :dependent => :destroy
31
+ end
32
+ class PageRoute
33
+ has_many :requirements, :class_name => "PageRouteRequirement", :dependent => :destroy
34
+ has_many :conditions, :class_name => "PageRouteCondition", :dependent => :destroy
35
+ end
36
+
37
+ # Added these here because these classes will be removed by the next commit, so if anyone tried to run this script in future versions it would have a missing constant error unless we keep these class definitions around
38
+ class BlogPostsInCategoryPortlet < Portlet; end
39
+ class BlogPostsWithTagPortlet < Portlet; end
40
+ class BlogPostPortlet < Portlet; end
41
+ class BlogPostsInDayPortlet < Portlet; end
42
+ class BlogPostsInMonthPortlet < Portlet; end
43
+ class BlogPostsInYearPortlet < Portlet; end
44
+
45
+ class MigrateTo20100427 < ActiveRecord::Migration
46
+ def self.up
47
+ drop_table :blog_group_membership_versions
48
+
49
+ PageRouteOption.all.each {|a| a.destroy unless a.page_route }
50
+
51
+ puts "Destroying portlets, pages, page_routes left over from old version of bcms_blog..."
52
+ puts "(*Not* destroying any existing Blogs, pages on which Blogs are connected, or BlogPosts)"
53
+ portlets = [BlogPostPortlet, BlogPostsInCategoryPortlet, BlogPostsWithTagPortlet, BlogPostsInDayPortlet, BlogPostsInMonthPortlet, BlogPostsInYearPortlet]
54
+ #pp portlets.map(&:all).flatten.map(&:connected_pages).flatten.map(&:page_routes).flatten.each(&:destroy)
55
+ pp portlets.map(&:all).flatten.map(&:connected_pages).flatten.each(&:destroy)
56
+ pp portlets.map(&:all).flatten.each(&:destroy)
57
+
58
+ # Something like this might not work if they have moved their Blog page to a different section or to no section, so we better let users resolve this manually...
59
+ #Blog.all.map(&:connected_pages).flatten.each do |page|
60
+ # page.hidden = true
61
+ # page.save!
62
+ # page.section.hidden = false
63
+ # page.section.save!
64
+ #end
65
+
66
+ puts "Calling after_create on each Blog in the system..."
67
+ Blog.all.each do |blog|
68
+ puts "#{blog}..."
69
+ blog.send :after_create
70
+ end
71
+ end
72
+
73
+ def self.down
74
+ end
75
+ end
76
+
77
+ MigrateTo20100427.up
@@ -0,0 +1,40 @@
1
+ v1.1.0
2
+
3
+ This version introduces significant changes and improvements over version 1.0.0
4
+ and lays the groundwork for a more sophisticated blogging platform for BrowserCMS.
5
+
6
+ Notable Features:
7
+ =================
8
+
9
+ 1. A Blog and supporting structure (sections, pages, page routes, etc.) and data are no longer
10
+ created as part of the modules's installation process. When running the module's migrations,
11
+ only the following items are created:
12
+
13
+ * blogs, blog_posts and blog_comment tables (and corresponding tables to hold versioning data)
14
+ * blog_group_memberships table
15
+ * Blog, BlogPost and BlogComment content types
16
+ * Blog Post category type
17
+
18
+ 2. It is only until a Blog is created when a corresponding section, pages, page routes and portlets are created.
19
+ Each blog has its own section, pages and page routes, which allows for multiple blogs to be created.
20
+
21
+ 3. It is now possible to add attachments to blog posts.
22
+
23
+ 4. Comments are moderated by default using BrowserCMS' default behaviors. However, when creating a Blog,
24
+ users can specify whether comments should be published automatically.
25
+
26
+ 5. The module now uses BrowserCMS' permissions framework to specify if a particular user is able to
27
+ create or edit Blogs and BlogPosts.
28
+
29
+ 6. Portlets have been improved to match common standard blog publishing templates.
30
+
31
+ For a complete rundown and rationale behind the changes introduced, please refer to:
32
+ https://browsermedia.lighthouseapp.com/projects/28481/tickets/163-review-and-integrate-changes-to-the-blog-module
33
+
34
+ Contributors:
35
+ =============
36
+ Tyler Rick
37
+ Jon Leighton
38
+
39
+
40
+ v1.0.0
@@ -0,0 +1 @@
1
+ require 'bcms_blog/routes'
@@ -0,0 +1,9 @@
1
+ module Cms::Routes
2
+ def routes_for_bcms_blog
3
+ namespace(:cms) do |cms|
4
+ cms.content_blocks :blogs
5
+ cms.content_blocks :blog_posts
6
+ cms.content_blocks :blog_comments
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ gem_root = File.expand_path(File.join(File.dirname(__FILE__), ".."))
2
+ Cms.add_to_rails_paths gem_root
3
+ Cms.add_generator_paths gem_root, "db/migrate/[0-9]*_*.rb"
4
+ ApplicationHelper.module_eval { include Cms::BlogHelper }
@@ -0,0 +1,48 @@
1
+ if ActiveRecord::Base.connection.table_exists?("blogs")
2
+
3
+ Factory.define :group do |m|
4
+ m.sequence(:name) {|n| "TestGroup#{n}" }
5
+ m.association :group_type
6
+ end
7
+
8
+ Factory.define :group_type do |m|
9
+ m.sequence(:name) {|n| "TestGroupType#{n}" }
10
+ end
11
+
12
+ Factory.define :permission do |m|
13
+ m.name "edit_content"
14
+ end
15
+
16
+ Factory.define :user do |m|
17
+ m.first_name "Test"
18
+ m.last_name "User"
19
+ m.sequence(:login) {|n| "test_#{n}" }
20
+ m.email {|a| "#{a.login}@example.com" }
21
+ m.password "password"
22
+ m.password_confirmation {|a| a.password }
23
+ end
24
+
25
+ Factory.define :section do |m|
26
+ m.name "A Section"
27
+ m.path "/a-section"
28
+ end
29
+
30
+ Factory.define :blog do |m|
31
+ m.sequence(:name) {|n| "TestBlog#{n}"}
32
+ m.moderate_comments true
33
+ end
34
+
35
+ Factory.define :blog_post do |m|
36
+ m.sequence(:name) { |n| "BlogPost#{n}" }
37
+ m.blog {|b| b.association(:blog) }
38
+ m.sequence(:body) { |n| "Lorem ipsum #{n}" }
39
+ m.association :author, :factory => :user
40
+ end
41
+
42
+ Factory.define :blog_comment do |m|
43
+ m.name "Just a comment"
44
+ m.body "Nice blog"
45
+ m.association :post, :factory => :blog_post
46
+ m.association :author, :factory => :user
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class BlogPostTest < ActionController::TestCase
4
+ tests Cms::ContentController
5
+
6
+ def setup
7
+ setup_stubs
8
+ create_baseline_data
9
+ end
10
+
11
+ # def teardown
12
+ # destroy_baseline_data
13
+ # end
14
+
15
+ def test_show_post
16
+ get :show, :path => ["blog", "post"],
17
+ :year => @first_post.year,
18
+ :month => @first_post.month,
19
+ :day => @first_post.day,
20
+ :slug => @first_post.slug
21
+ #log @response.body
22
+ assert_response :success
23
+ assert_select "title", @first_post.name
24
+ assert_select ".blog_post", 1
25
+
26
+ assert_select "#blog_post_#{@first_post.id}" do
27
+ assert_select "h2 a", @first_post.name
28
+ assert_select "p.body", @first_post.body
29
+ assert_select "p.meta a", "General"
30
+ assert_select "p.meta a", "0 Comments"
31
+ end
32
+
33
+ end
34
+
35
+ # def test_non_existent_slug_should_return_404
36
+ # get :show, :path => ["blog", "post"],
37
+ # :year => 2005, :month => 6, :day => 14,
38
+ # :slug => "not-here"
39
+ # assert_response :not_found
40
+ # end
41
+
42
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class BlogTest < ActionController::TestCase
4
+ tests Cms::ContentController
5
+
6
+ def setup
7
+ # create_baseline_data
8
+ # `rake db:test:purge`
9
+ # `rake db:migrate`
10
+ create_baseline_data
11
+ end
12
+ #
13
+ # def teardown
14
+ # destroy_baseline_data
15
+ # end
16
+ #
17
+ def test_list_of_blog_posts
18
+
19
+
20
+ get :show
21
+ log @response.body
22
+ assert_response :success
23
+ assert_select ".blog_post", 5
24
+
25
+ assert_select "#blog_post_#{@first_post.id}" do
26
+ assert_select "h2 a", @first_post.name
27
+ assert_select "p.body", @first_post.body
28
+ assert_select "p.meta a", "General"
29
+ assert_select "p.meta a", "0 Comments"
30
+ end
31
+
32
+ assert_select "#blog_post_#{@foo_post_1.id}" do
33
+ assert_select "h2 a", @foo_post_1.name
34
+ assert_select "p.body", @foo_post_1.body
35
+ assert_select "p.meta .tags a", "foo"
36
+ assert_select "p.meta .tags a", "stuff"
37
+ end
38
+ end
39
+
40
+ # def test_list_of_tagged_blog_posts
41
+ # get :show, :category => "General"
42
+ # puts @response.body
43
+ # assert_response :success
44
+ # assert_select ".blog_post", 3
45
+ # end
46
+ #
47
+ # def test_list_of_categorized_blog_posts
48
+ # get :show, :tag => "foo"
49
+ # #log @response.body
50
+ # assert_response :success
51
+ # assert_select ".blog_post", 2
52
+ # end
53
+ #
54
+ # def test_list_of_blog_posts_in_day
55
+ # get :show, :path => ["blog", "posts_in_day"],
56
+ # :year => 2008, :month => 7, :day => 5
57
+ # assert_response :success
58
+ # assert_select ".blog_post", 2
59
+ # end
60
+ #
61
+ # def test_list_of_blog_posts_in_month
62
+ # get :show, :path => ["blog", "posts_in_month"],
63
+ # :year => 2008, :month => 7
64
+ # assert_response :success
65
+ # assert_select ".blog_post", 3
66
+ # end
67
+ #
68
+ # def test_list_of_blog_posts_in_year
69
+ # get :show, :path => ["blog", "posts_in_year"],
70
+ # :year => 2008
71
+ # assert_response :success
72
+ # assert_select ".blog_post", 4
73
+ # end
74
+ end