From 12b82c088c310e5100cd5c7861709b019da19b97 Mon Sep 17 00:00:00 2001 From: Antonio Terceiro Date: Fri, 14 May 2010 09:46:37 -0300 Subject: [PATCH] Added RSS feed per tag --- app/controllers/public/profile_controller.rb | 13 +++++++++++++ app/helpers/application_helper.rb | 9 +++------ app/models/blog.rb | 2 +- app/models/rss_feed.rb | 49 +++++++------------------------------------------ app/views/cms/_blog.rhtml | 1 - app/views/content_viewer/blog_page.rhtml | 2 ++ app/views/content_viewer/view_page.rhtml | 6 ++++++ app/views/layouts/application-ng.rhtml | 2 +- app/views/layouts/application.rhtml | 2 +- app/views/profile/tag.rhtml | 6 ++++++ config/routes.rb | 3 +++ features/profile_tags.feature | 20 ++++++++++++++++++++ features/support/paths.rb | 3 +++ lib/feed_writer.rb | 37 +++++++++++++++++++++++++++++++++++++ test/unit/blog_test.rb | 6 ------ test/unit/feed_writer_test.rb | 26 ++++++++++++++++++++++++++ test/unit/rss_feed_test.rb | 35 +---------------------------------- 17 files changed, 130 insertions(+), 92 deletions(-) create mode 100644 features/profile_tags.feature create mode 100644 lib/feed_writer.rb create mode 100644 test/unit/feed_writer_test.rb diff --git a/app/controllers/public/profile_controller.rb b/app/controllers/public/profile_controller.rb index 20de316..da329f1 100644 --- a/app/controllers/public/profile_controller.rb +++ b/app/controllers/public/profile_controller.rb @@ -29,6 +29,19 @@ class ProfileController < PublicController end end + def tag_feed + @tag = params[:id] + tagged = profile.find_tagged_with(@tag).paginate(:per_page => 20, :page => 1) + feed_writer = FeedWriter.new + data = feed_writer.write( + tagged, + :title => _("%s's contents tagged with \"%s\"") % [profile.name, @tag], + :description => _("%s's contents tagged with \"%s\"") % [profile.name, @tag], + :link => url_for(:action => 'tag') + ) + render :text => data, :content_type => "text/xml" + end + def communities if is_cache_expired?(profile.communities_cache_key(params)) @communities = profile.communities.paginate(:per_page => per_page, :page => params[:npage]) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 75fc1f8..bde5a7a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -869,12 +869,9 @@ module ApplicationHelper article_helper.cms_label_for_edit end - def meta_tags_for_article(article) - if @controller.controller_name == 'content_viewer' - if article and (article.blog? or (article.parent and article.parent.blog?)) - blog = article.blog? ? article : article.parent - "" - end + def add_rss_feed_to_head(title, url) + content_for :feeds do + "" end end diff --git a/app/models/blog.rb b/app/models/blog.rb index 156d8f3..35b09f4 100644 --- a/app/models/blog.rb +++ b/app/models/blog.rb @@ -6,7 +6,7 @@ class Blog < Folder attr_accessor :filter after_create do |blog| - blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile, :feed_item_description => 'body') + blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile) blog.feed = blog.feed_attrs end diff --git a/app/models/rss_feed.rb b/app/models/rss_feed.rb index 2798c6e..4172ad3 100644 --- a/app/models/rss_feed.rb +++ b/app/models/rss_feed.rb @@ -41,16 +41,6 @@ class RssFeed < Article end validates_inclusion_of :include, :in => [ 'all', 'parent_and_children' ], :if => :include - # determinates what to include in the feed as items' description. Possible - # values are +:body+ (default) and +:abstract+. - def feed_item_description - settings[:feed_item_description] - end - def feed_item_description=(value) - settings[:feed_item_description] = value - end - validates_inclusion_of :feed_item_description, :in => [ 'body', 'abstract' ], :if => :feed_item_description - # TODO def to_html(options = {}) end @@ -74,38 +64,13 @@ class RssFeed < Article end end def data - articles = fetch_articles - result = "" - xml = Builder::XmlMarkup.new(:target => result) - - xml.instruct! :xml, :version=>"1.0" - xml.rss(:version=>"2.0") do - xml.channel do - xml.title(_("%s's RSS feed") % (self.profile.name)) - xml.link(url_for(self.profile.url)) - xml.description(_("%s's content published at %s") % [self.profile.name, self.profile.environment.name]) - xml.language("pt_BR") - for article in articles - unless self == article - xml.item do - xml.title(article.name) - if self.feed_item_description == 'body' - xml.description(article.to_html) - else - xml.description(article.abstract) - end - # rfc822 - xml.pubDate(article.created_at.rfc2822) - # link to article - xml.link(url_for(article.url)) - xml.guid(url_for(article.url)) - end - end - end - end - end - - result + articles = fetch_articles.select { |a| a != self } + FeedWriter.new.write( + articles, + :title => _("%s's RSS feed") % (self.profile.name), + :description => _("%s's content published at %s") % [self.profile.name, self.profile.environment.name], + :link => url_for(self.profile.url) + ) end def self.short_description diff --git a/app/views/cms/_blog.rhtml b/app/views/cms/_blog.rhtml index f9993aa..f234b43 100644 --- a/app/views/cms/_blog.rhtml +++ b/app/views/cms/_blog.rhtml @@ -56,7 +56,6 @@ <% f.fields_for 'feed', @article.feed do |feed| %> <%= labelled_form_field(_('Limit of posts in RSS Feed'), feed.select(:limit, [5, 10, 20, 50])) %> - <%= labelled_form_field(_('Use as description in RSS Feed:'), feed.select(:feed_item_description, [ [ _('Article body'), 'body'], [ _('Article abstract'), 'abstract'] ])) %> <% end %> <% f.fields_for 'external_feed_builder', @article.external_feed do |efeed| %> diff --git a/app/views/content_viewer/blog_page.rhtml b/app/views/content_viewer/blog_page.rhtml index 9fb09cf..98f4563 100644 --- a/app/views/content_viewer/blog_page.rhtml +++ b/app/views/content_viewer/blog_page.rhtml @@ -1,3 +1,5 @@ +<% add_rss_feed_to_head(article.name, article.feed.url) if article.blog? && article.feed %> + <%= content_tag('em', _('(external feed was not loaded yet)'), :id => 'external-feed-info', :class => 'metadata') if article.blog? && article.external_feed && article.external_feed.enabled && article.external_feed.fetched_at.nil? %>
diff --git a/app/views/content_viewer/view_page.rhtml b/app/views/content_viewer/view_page.rhtml index f607392..580b2bd 100644 --- a/app/views/content_viewer/view_page.rhtml +++ b/app/views/content_viewer/view_page.rhtml @@ -1,3 +1,9 @@ +<% + if @page.parent && @page.parent.blog? && @page.parent.feed + add_rss_feed_to_head(@page.parent.name, @page.parent.feed.url) + end +%> +
<% diff --git a/app/views/layouts/application-ng.rhtml b/app/views/layouts/application-ng.rhtml index 439c765..7363c63 100644 --- a/app/views/layouts/application-ng.rhtml +++ b/app/views/layouts/application-ng.rhtml @@ -2,7 +2,7 @@ <%= h page_title %> - <%= meta_tags_for_article(@page) %> + <%= yield(:feeds) %> diff --git a/app/views/layouts/application.rhtml b/app/views/layouts/application.rhtml index 3bb65c3..cb27f08 100644 --- a/app/views/layouts/application.rhtml +++ b/app/views/layouts/application.rhtml @@ -6,7 +6,7 @@ - <%= meta_tags_for_article(@page) %> + <%= yield(:feeds) %> <%= noosfero_javascript %> <%= javascript_include_tag 'menu', 'auto-open-menu', 'menu-config', :cache => 'cache-menu' %> diff --git a/app/views/profile/tag.rhtml b/app/views/profile/tag.rhtml index 581c1da..a8d8427 100644 --- a/app/views/profile/tag.rhtml +++ b/app/views/profile/tag.rhtml @@ -1,5 +1,11 @@ +<% add_rss_feed_to_head(_("%s's contents tagged with \"%s\"") % [profile.name, @tag], tag_feed_path) %> +

<%= _('Content tagged with "%s"') % @tag %>

+

+<%= link_to image_tag('icons-mime/rss-feed.png', :alt => _('Feed for this tag'), :title => _('Feed for this tag')), tag_feed_path, :class => 'blog-feed-link'%> +

+ <% cache_timeout(@tag_cache_key, 4.hour.from_now) do %>
    diff --git a/config/routes.rb b/config/routes.rb index 0f172e9..2c42c82 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -65,6 +65,9 @@ ActionController::Routing::Routes.draw do |map| # invite map.invite 'profile/:profile/invite/:action', :controller => 'invite', :profile => /#{Noosfero.identifier_format}/ + # feeds per tag + map.tag_feed 'profile/:profile/tag/:id/feed', :controller => 'profile', :action =>'tag_feed', :id => /.*/, :profile => /#{Noosfero.identifier_format}/ + # public profile information map.profile 'profile/:profile/:action/:id', :controller => 'profile', :action => 'index', :id => /.*/, :profile => /#{Noosfero.identifier_format}/ diff --git a/features/profile_tags.feature b/features/profile_tags.feature new file mode 100644 index 0000000..43fd80f --- /dev/null +++ b/features/profile_tags.feature @@ -0,0 +1,20 @@ +Feature: profile tags + As a Noosfero user + I want to to view content tagged + So that I can follow the subjects I care about + + Background: + Given the following users + | login | + | terceiro | + And the following articles + | owner | name | body | tag_list | + | terceiro | text 1 | text 1 content | tag1, tag2 | + | terceiro | text 2 | text 2 content | tag1, tag3 | + + Scenario: tag feed + When I go to terceiro's profile + And I follow "tag1" + And I follow "Feed for this tag" + Then I should see "text 1" + And I should see "text 2" diff --git a/features/support/paths.rb b/features/support/paths.rb index 3417932..8514042 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -30,6 +30,9 @@ module NavigationHelpers when /^(.*)'s sitemap/ '/profile/%s/sitemap' % Profile.find_by_name($1).identifier + when /^(.*)'s profile/ + '/profile/%s' % Profile.find_by_name($1).identifier + when /^login page$/ '/account/login' diff --git a/lib/feed_writer.rb b/lib/feed_writer.rb new file mode 100644 index 0000000..ee6eb89 --- /dev/null +++ b/lib/feed_writer.rb @@ -0,0 +1,37 @@ +class FeedWriter + + include ActionController::UrlWriter + + def write(articles, options = {}) + result = "" + xml = Builder::XmlMarkup.new(:target => result) + + xml.instruct! :xml, :version=>"1.0" + xml.rss(:version=>"2.0") do + xml.channel do + xml.title(options[:title] || _('Feed')) + if options[:link] + xml.link(options[:link]) + end + if options[:description] + xml.description(options[:description]) + end + for article in articles + xml.item do + xml.title(article.name) + xml.description(article.to_html) + if article.created_at + # rfc822 + xml.pubDate(article.created_at.rfc2822) + end + # link to article + xml.link(url_for(article.url)) + xml.guid(url_for(article.url)) + end + end + end + end + + result + end +end diff --git a/test/unit/blog_test.rb b/test/unit/blog_test.rb index 8d357b6..b055d07 100644 --- a/test/unit/blog_test.rb +++ b/test/unit/blog_test.rb @@ -32,12 +32,6 @@ class BlogTest < ActiveSupport::TestCase assert_kind_of RssFeed, b.feed end - should 'include articles body in feed by default' do - p = create_user('testuser').person - b = Blog.create!(:profile => p, :name => 'blog_feed_test') - assert_equal 'body', b.feed.feed_item_description - end - should 'save feed options' do p = create_user('testuser').person p.articles << Blog.new(:profile => p, :name => 'blog_feed_test') diff --git a/test/unit/feed_writer_test.rb b/test/unit/feed_writer_test.rb new file mode 100644 index 0000000..6d72558 --- /dev/null +++ b/test/unit/feed_writer_test.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class FeedWriterTest < Test::Unit::TestCase + + should 'generate feeds' do + articles = [] + profile = fast_create(:profile, :identifier => "tagger") + articles << fast_create(:article, :name => 'text 1', :slug => 'text-1', :path => 'text-1', :profile_id => profile.id) + articles << fast_create(:article, :name => 'text 2', :slug => 'text-2', :path => 'text-2', :profile_id => profile.id) + writer = FeedWriter.new + + feed = writer.write(articles) + assert_match('text 1', feed) + assert_match('/tagger/' + articles.first.slug, feed) + end + + should 'use title, link and description' do + writer = FeedWriter.new + rss = writer.write([], :title => "my title", :description => "my description", :link => "http://example.com/") + assert_match("my title", rss) + assert_match("my description", rss) + assert_match("http://example.com/", rss) + end + +end + diff --git a/test/unit/rss_feed_test.rb b/test/unit/rss_feed_test.rb index 8d6f5cd..680710a 100644 --- a/test/unit/rss_feed_test.rb +++ b/test/unit/rss_feed_test.rb @@ -62,24 +62,6 @@ class RssFeedTest < Test::Unit::TestCase feed.data end - should 'be able to choose to put abstract or entire body on feed' do - profile = create_user('testuser').person - a1 = profile.articles.build(:name => 'article 1', 'abstract' => 'my abstract', 'body' => 'my text'); a1.save! - - feed = RssFeed.new(:name => 'testfeed') - feed.profile = profile - feed.save! - - rss = feed.data - assert_match /my abstract<\/description>/, rss - assert_no_match /my text<\/description>/, rss - - feed.feed_item_description = 'body' - rss = feed.data - assert_match /my text<\/description>/, rss - assert_no_match /my abstract<\/description>/, rss - end - should "be able to search only children of feed's parent" do profile = create_user('testuser').person a1 = profile.articles.build(:name => 'article 1'); a1.save! @@ -201,21 +183,6 @@ class RssFeedTest < Test::Unit::TestCase assert !feed.errors.invalid?(:include) end - should 'allow only body and abstract as feed_item_description' do - feed = RssFeed.new - feed.feed_item_description = :something_else - feed.valid? - assert feed.errors.invalid?(:feed_item_description) - - feed.feed_item_description = 'body' - feed.valid? - assert !feed.errors.invalid?(:feed_item_description) - - feed.feed_item_description = 'abstract' - feed.valid? - assert !feed.errors.invalid?(:feed_item_description) - end - should 'provide proper short description' do assert_kind_of String, RssFeed.short_description end @@ -246,7 +213,7 @@ class RssFeedTest < Test::Unit::TestCase blog = fast_create(Blog, :profile_id => profile.id) published_article = PublishedArticle.create!(:reference_article => article, :profile => profile) blog.posts << published_article - feed = RssFeed.new(:parent => blog, :profile => profile, :feed_item_description => 'body') + feed = RssFeed.new(:parent => blog, :profile => profile) assert_match published_article.to_html, feed.data end -- libgit2 0.21.2