Commit cb67a972189432ac6d5d0b1e9b3ef13f9d3cff40
Committed by
Antonio Terceiro
1 parent
d2c9927d
Exists in
staging
and in
42 other branches
ActionItem904: removing unpublished posts from blogs and feeds
* For blog owner, unpublished articles are listed with hachures and opacity
Showing
15 changed files
with
153 additions
and
46 deletions
Show diff stats
app/helpers/blog_helper.rb
| ... | ... | @@ -14,4 +14,25 @@ module BlogHelper |
| 14 | 14 | _('Edit blog') |
| 15 | 15 | end |
| 16 | 16 | |
| 17 | + def list_posts(user, articles) | |
| 18 | + pagination = will_paginate(articles, { | |
| 19 | + :param_name => 'npage', | |
| 20 | + :prev_label => _('« Newer posts'), | |
| 21 | + :next_label => _('Older posts »') | |
| 22 | + }) | |
| 23 | + content = [] | |
| 24 | + articles.map{ |i| | |
| 25 | + css_add = '' | |
| 26 | + if i.published? || (user==i.profile) | |
| 27 | + css_add = '-not-published' if !i.published? | |
| 28 | + content << content_tag('div', display_post(i), :class => 'blog-post' + css_add, :id => "post-#{i.id}") | |
| 29 | + end | |
| 30 | + } | |
| 31 | + content.join("\n") + (pagination or '') | |
| 32 | + end | |
| 33 | + | |
| 34 | + def display_post(article) | |
| 35 | + article_title(article) + content_tag('p', article.to_html) + | |
| 36 | + content_tag('p', link_to( number_of_comments(article), article.url.merge(:form => 'opened', :anchor => 'comment_form') ), :class => 'metadata') | |
| 37 | + end | |
| 17 | 38 | end | ... | ... |
app/helpers/content_viewer_helper.rb
| 1 | 1 | module ContentViewerHelper |
| 2 | 2 | |
| 3 | 3 | include GetText |
| 4 | + include BlogHelper | |
| 4 | 5 | |
| 5 | 6 | def number_of_comments(article) |
| 6 | 7 | n = article.comments.size |
| ... | ... | @@ -24,37 +25,10 @@ module ContentViewerHelper |
| 24 | 25 | title |
| 25 | 26 | end |
| 26 | 27 | |
| 27 | - def list_posts(articles) | |
| 28 | - pagination = will_paginate(articles, { | |
| 29 | - :param_name => 'npage', | |
| 30 | - :page_links => false, | |
| 31 | - :prev_label => _('Newer posts »'), | |
| 32 | - :next_label => _('« Older posts') | |
| 33 | - }) | |
| 34 | - articles.map{ |i| content_tag('div', display_post(i), :class => 'blog-post', :id => "post-#{i.id}") }.join("\n") + | |
| 35 | - (pagination or '') | |
| 36 | - end | |
| 37 | - | |
| 38 | - def display_post(article) | |
| 39 | - article_title(article) + content_tag('p', article.to_html) + | |
| 40 | - content_tag('p', link_to( number_of_comments(article), article.url.merge(:form => 'opened', :anchor => 'comment_form') ), :class => 'metadata') | |
| 41 | - end | |
| 42 | - | |
| 43 | 28 | def article_to_html(article) |
| 44 | - content = article.to_html | |
| 29 | + content = article.to_html(:page => params[:npage]) | |
| 45 | 30 | return self.instance_eval(&content) if content.kind_of?(Proc) |
| 46 | - | |
| 47 | - if article.blog? | |
| 48 | - children = if article.filter and article.filter[:year] and article.filter[:month] | |
| 49 | - filter_date = DateTime.parse("#{article.filter[:year]}-#{article.filter[:month]}-01") | |
| 50 | - article.posts.paginate :page => params[:npage], :per_page => article.posts_per_page, :conditions => [ 'created_at between ? and ?', filter_date, filter_date + 1.month - 1.day ] | |
| 51 | - else | |
| 52 | - article.posts.paginate :page => params[:npage], :per_page => article.posts_per_page | |
| 53 | - end | |
| 54 | - content + (children.compact.empty? ? content_tag('em', _('(no posts)')) : list_posts(children)) | |
| 55 | - else | |
| 56 | - content | |
| 57 | - end | |
| 31 | + content | |
| 58 | 32 | end |
| 59 | 33 | |
| 60 | 34 | end | ... | ... |
app/models/article.rb
| ... | ... | @@ -127,7 +127,7 @@ class Article < ActiveRecord::Base |
| 127 | 127 | # The implementation in this class just provides the +body+ attribute as the |
| 128 | 128 | # HTML. Other article types can override this method to provide customized |
| 129 | 129 | # views of themselves. |
| 130 | - def to_html | |
| 130 | + def to_html(options = {}) | |
| 131 | 131 | body |
| 132 | 132 | end |
| 133 | 133 | ... | ... |
app/models/blog.rb
| ... | ... | @@ -28,8 +28,8 @@ class Blog < Folder |
| 28 | 28 | |
| 29 | 29 | # FIXME isn't this too much including just to be able to generate some HTML? |
| 30 | 30 | include ActionView::Helpers::TagHelper |
| 31 | - def to_html | |
| 32 | - content_tag('div', body) + tag('hr') | |
| 31 | + def to_html(options = {}) | |
| 32 | + posts_list(options[:page]) | |
| 33 | 33 | end |
| 34 | 34 | |
| 35 | 35 | def folder? |
| ... | ... | @@ -52,4 +52,16 @@ class Blog < Folder |
| 52 | 52 | end |
| 53 | 53 | end |
| 54 | 54 | |
| 55 | + def posts_list(npage) | |
| 56 | + article = self | |
| 57 | + children = if filter and filter[:year] and filter[:month] | |
| 58 | + filter_date = DateTime.parse("#{filter[:year]}-#{filter[:month]}-01") | |
| 59 | + posts.paginate :page => npage, :per_page => posts_per_page, :conditions => [ 'created_at between ? and ?', filter_date, filter_date + 1.month - 1.day ] | |
| 60 | + else | |
| 61 | + posts.paginate :page => npage, :per_page => posts_per_page | |
| 62 | + end | |
| 63 | + lambda do | |
| 64 | + render :file => 'content_viewer/blog_page', :locals => {:article => article, :children => children} | |
| 65 | + end | |
| 66 | + end | |
| 55 | 67 | end | ... | ... |
app/models/enterprise_homepage.rb
| ... | ... | @@ -20,7 +20,7 @@ class EnterpriseHomepage < Article |
| 20 | 20 | include EnterpriseHomepageHelper |
| 21 | 21 | include CatalogHelper |
| 22 | 22 | |
| 23 | - def to_html | |
| 23 | + def to_html(options ={}) | |
| 24 | 24 | products = self.profile.products |
| 25 | 25 | display_profile_info(self.profile) + content_tag('div', self.body || '') + |
| 26 | 26 | (self.profile.environment.enabled?('disable_products_for_enterprises') ? '' : display_products_list(self.profile, products)) | ... | ... |
app/models/event.rb
app/models/folder.rb
app/models/rss_feed.rb
| ... | ... | @@ -50,7 +50,7 @@ class RssFeed < Article |
| 50 | 50 | validates_inclusion_of :feed_item_description, :in => [ 'body', 'abstract' ], :if => :feed_item_description |
| 51 | 51 | |
| 52 | 52 | # TODO |
| 53 | - def to_html | |
| 53 | + def to_html(options = {}) | |
| 54 | 54 | end |
| 55 | 55 | |
| 56 | 56 | # RSS feeds have type =text/xml=. |
| ... | ... | @@ -61,7 +61,7 @@ class RssFeed < Article |
| 61 | 61 | include ActionController::UrlWriter |
| 62 | 62 | def fetch_articles |
| 63 | 63 | if parent && parent.blog? |
| 64 | - return parent.posts.find(:all, :limit => self.limit, :order => 'id desc') | |
| 64 | + return parent.posts.find(:all, :conditions => ['published = ?', true], :limit => self.limit, :order => 'id desc') | |
| 65 | 65 | end |
| 66 | 66 | |
| 67 | 67 | articles = | ... | ... |
app/models/textile_article.rb
app/models/uploaded_file.rb
| ... | ... | @@ -50,7 +50,7 @@ class UploadedFile < Article |
| 50 | 50 | # FIXME isn't this too much including just to be able to generate some HTML? |
| 51 | 51 | include ActionView::Helpers::TagHelper |
| 52 | 52 | |
| 53 | - def to_html | |
| 53 | + def to_html(options = {}) | |
| 54 | 54 | tag('img', :src => public_filename, :class => css_class_name, :style => 'max-width: 100%') if image? |
| 55 | 55 | end |
| 56 | 56 | ... | ... |
public/stylesheets/article.css
| ... | ... | @@ -202,10 +202,38 @@ |
| 202 | 202 | |
| 203 | 203 | #content #article .pagination .prev_page { |
| 204 | 204 | position: absolute; |
| 205 | - right: 0; | |
| 205 | + left: 0; | |
| 206 | 206 | } |
| 207 | 207 | |
| 208 | 208 | #content #article .pagination .next_page { |
| 209 | 209 | position: absolute; |
| 210 | - left: 0; | |
| 210 | + right: 0; | |
| 211 | +} | |
| 212 | +.msie6 #content #article .pagination .prev_page, | |
| 213 | +.msie6 #content #article .pagination .next_page { | |
| 214 | + position: relative; | |
| 215 | + display: inline; | |
| 216 | +} | |
| 217 | + | |
| 218 | +/* NOT PUBLISHED BLOG POSTS */ | |
| 219 | + | |
| 220 | +.blog-post-not-published { | |
| 221 | + background: url(/images/hachure.png); | |
| 222 | + opacity: 0.25; | |
| 223 | + filter: alpha(opacity=25); | |
| 224 | + zoom: 1; | |
| 225 | +} | |
| 226 | + | |
| 227 | +.blog-post-not-published a { | |
| 228 | + text-decoration: none; | |
| 229 | +} | |
| 230 | + | |
| 231 | +#content .blog-post-not-published .created-at { | |
| 232 | + text-align: left; | |
| 233 | +} | |
| 234 | + | |
| 235 | +.blog-post-not-published .metadata { | |
| 236 | + display: block; | |
| 237 | + text-align: center; | |
| 238 | + font-size: small; | |
| 211 | 239 | } | ... | ... |
test/unit/blog_helper_test.rb
| ... | ... | @@ -6,12 +6,64 @@ class BlogHelperTest < Test::Unit::TestCase |
| 6 | 6 | |
| 7 | 7 | def setup |
| 8 | 8 | stubs(:show_date).returns('') |
| 9 | + @environment = Environment.default | |
| 9 | 10 | @profile = create_user('blog_helper_test').person |
| 11 | + @blog = Blog.create!(:profile => profile, :name => 'Blog test') | |
| 10 | 12 | end |
| 13 | + | |
| 11 | 14 | attr :profile |
| 15 | + attr :blog | |
| 16 | + | |
| 17 | + def _(s); s; end | |
| 18 | + | |
| 19 | + should 'list published posts with class blog-post' do | |
| 20 | + blog.children << published_post = TextileArticle.create!(:name => 'Post', :profile => profile, :parent => blog, :published => true) | |
| 12 | 21 | |
| 13 | - should 'add real tests' do | |
| 14 | - assert true | |
| 22 | + expects(:display_post).with(anything).returns('POST') | |
| 23 | + expects(:content_tag).with('div', 'POST', :class => 'blog-post', :id => "post-#{published_post.id}").returns('RESULT') | |
| 24 | + | |
| 25 | + assert_equal 'RESULT', list_posts(profile, blog.posts) | |
| 15 | 26 | end |
| 16 | 27 | |
| 28 | + should 'list unpublished posts to owner with a different class' do | |
| 29 | + blog.children << unpublished_post = TextileArticle.create!(:name => 'Post', :profile => profile, :parent => blog, :published => false) | |
| 30 | + | |
| 31 | + expects(:display_post).with(anything).returns('POST') | |
| 32 | + expects(:content_tag).with('div', 'POST', :class => 'blog-post-not-published', :id => "post-#{unpublished_post.id}").returns('RESULT') | |
| 33 | + | |
| 34 | + assert_equal 'RESULT', list_posts(profile, blog.posts) | |
| 35 | + end | |
| 36 | + | |
| 37 | + should 'not list unpublished posts to not owner' do | |
| 38 | + blog.children << unpublished_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => blog, :published => false) | |
| 39 | + | |
| 40 | + blog.children << published_post = TextileArticle.create!(:name => 'Second post', :profile => profile, :parent => blog, :published => true) | |
| 41 | + | |
| 42 | + expects(:display_post).with(anything).returns('POST') | |
| 43 | + expects(:content_tag).with('div', 'POST', :class => 'blog-post', :id => "post-#{published_post.id}").returns('RESULT') | |
| 44 | + expects(:content_tag).with('div', 'POST', :class => 'blog-post-not-published', :id => "post-#{unpublished_post.id}").never | |
| 45 | + | |
| 46 | + assert_equal 'RESULT', list_posts(nil, blog.posts) | |
| 47 | + end | |
| 48 | + | |
| 49 | + should 'display post' do | |
| 50 | + blog.children << article = TextileArticle.create!(:name => 'Second post', :profile => profile, :parent => blog, :published => true) | |
| 51 | + expects(:article_title).with(article).returns('TITLE') | |
| 52 | + expects(:content_tag).with('p', article.to_html).returns(' TO_HTML') | |
| 53 | + expects(:number_of_comments).with(article).returns('NUMBER OF COMMENTS') | |
| 54 | + expects(:content_tag).with('p', 'NUMBER OF COMMENTS', anything).returns(' COMMENTS').at_least_once | |
| 55 | + | |
| 56 | + assert_equal 'TITLE TO_HTML COMMENTS', display_post(article) | |
| 57 | + end | |
| 58 | + | |
| 59 | + def will_paginate(arg1, arg2) | |
| 60 | + end | |
| 61 | + | |
| 62 | + def link_to(content, url) | |
| 63 | + content | |
| 64 | + end | |
| 65 | + | |
| 66 | + def content_tag(tag, content, options = {}) | |
| 67 | + "<#{tag}>#{content}</#{tag}>" | |
| 68 | + end | |
| 17 | 69 | end | ... | ... |
test/unit/content_viewer_helper_test.rb
| ... | ... | @@ -56,7 +56,7 @@ class ContentViewerHelperTest < Test::Unit::TestCase |
| 56 | 56 | should 'not list feed article' do |
| 57 | 57 | profile.articles << Blog.new(:name => 'Blog test') |
| 58 | 58 | assert_includes profile.blog.children.map{|i| i.class}, RssFeed |
| 59 | - result = list_posts(profile.blog.posts) | |
| 59 | + result = list_posts(nil, profile.blog.posts) | |
| 60 | 60 | assert_no_match /feed/, result |
| 61 | 61 | end |
| 62 | 62 | |
| ... | ... | @@ -75,10 +75,11 @@ class ContentViewerHelperTest < Test::Unit::TestCase |
| 75 | 75 | |
| 76 | 76 | self.stubs(:params).returns({:npage => nil}) |
| 77 | 77 | |
| 78 | + expects(:render).with(:file => 'content_viewer/blog_page', :locals => {:article => blog, :children => [nov]}).returns("BLI") | |
| 79 | + | |
| 78 | 80 | result = article_to_html(blog) |
| 79 | 81 | |
| 80 | - assert_match /November post/, result | |
| 81 | - assert_no_match /September post/, result | |
| 82 | + assert_equal 'BLI', result | |
| 82 | 83 | end |
| 83 | 84 | |
| 84 | 85 | end | ... | ... |
test/unit/rss_feed_test.rb
| ... | ... | @@ -121,6 +121,20 @@ class RssFeedTest < Test::Unit::TestCase |
| 121 | 121 | assert_equal [posts[5], posts[4], posts[3], posts[2], posts[1]], feed.fetch_articles |
| 122 | 122 | end |
| 123 | 123 | |
| 124 | + should 'list only published posts from blog' do | |
| 125 | + profile = create_user('testuser').person | |
| 126 | + blog = Blog.create(:name => 'blog', :profile => profile) | |
| 127 | + posts = [] | |
| 128 | + 5.times do |i| | |
| 129 | + posts << TextArticle.create!(:name => "post #{i}", :profile => profile, :parent => blog) | |
| 130 | + end | |
| 131 | + posts[0].published = false | |
| 132 | + posts[0].save! | |
| 133 | + | |
| 134 | + assert_equal [posts[4], posts[3], posts[2], posts[1]], blog.feed.fetch_articles | |
| 135 | + end | |
| 136 | + | |
| 137 | + | |
| 124 | 138 | should 'provide link to profile' do |
| 125 | 139 | profile = create_user('testuser').person |
| 126 | 140 | feed = RssFeed.new(:name => 'testfeed') | ... | ... |