From 722349c5cda1572768b3c1bbcaee412bfbbcec3b Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Wed, 19 Apr 2017 16:44:55 +0900 Subject: [PATCH] Make DataOutputAgent serve RSS output as `application/rss+xml` For backward compatibility, a new option `rss_content_type` is added and existing agents will have its value set to `text/xml`, which was the Content-Type value before this change. This fixes #1968. --- app/models/agents/data_output_agent.rb | 7 +++- .../20170419073748_set_rss_content_type.rb | 18 ++++++++++ spec/models/agents/data_output_agent_spec.rb | 35 +++++++++++++------ 3 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 db/migrate/20170419073748_set_rss_content_type.rb diff --git a/app/models/agents/data_output_agent.rb b/app/models/agents/data_output_agent.rb index 9e5aaa373a..fb37d728ba 100644 --- a/app/models/agents/data_output_agent.rb +++ b/app/models/agents/data_output_agent.rb @@ -27,6 +27,7 @@ class DataOutputAgent < Agent * `ttl` - A value for the \\ element in RSS output. (default: `60`) * `ns_media` - Add [yahoo media namespace](https://en.wikipedia.org/wiki/Media_RSS) in output xml * `ns_itunes` - Add [itunes compatible namespace](http://lists.apple.com/archives/syndication-dev/2005/Nov/msg00002.html) in output xml + * `rss_content_type` - Content-Type for RSS output (default: `application/rss+xml`) * `push_hubs` - Set to a list of PubSubHubbub endpoints you want to publish an update to every time this agent receives an event. (default: none) Popular hubs include [Superfeedr](https://pubsubhubbub.superfeedr.com/) and [Google](https://pubsubhubbub.appspot.com/). Note that publishing updates will make your feed URL known to the public, so if you want to keep it secret, set up a reverse proxy to serve your feed via a safe URL and specify it in `template.self`. If you'd like to output RSS tags with attributes, such as `enclosure`, use something like the following in your `template`: @@ -165,6 +166,10 @@ def feed_description interpolated['template']['description'].presence || "A feed of Events received by the '#{name}' Huginn Agent" end + def rss_content_type + interpolated['rss_content_type'].presence || 'application/rss+xml' + end + def xml_namespace namespaces = ['xmlns:atom="http://www.w3.org/2005/Atom"'] @@ -285,7 +290,7 @@ def receive_web_request(params, method, format) .to_xml(skip_types: true, root: "items", skip_instruct: true, indent: 1) .gsub(%r{^\n}, '') - return [<<-XML, 200, 'text/xml'] + return [<<-XML, 200, rss_content_type] diff --git a/db/migrate/20170419073748_set_rss_content_type.rb b/db/migrate/20170419073748_set_rss_content_type.rb new file mode 100644 index 0000000000..8a33bf0e89 --- /dev/null +++ b/db/migrate/20170419073748_set_rss_content_type.rb @@ -0,0 +1,18 @@ +class SetRssContentType < ActiveRecord::Migration[5.0] + def up + Agents::DataOutputAgent.find_each do |agent| + if agent.options['rss_content_type'].nil? + agent.options['rss_content_type'] = 'text/xml' + agent.save(validate: false) + end + end + end + + def down + Agents::DataOutputAgent.find_each do |agent| + if agent.options.delete('rss_content_type') + agent.save(validate: false) + end + end + end +end diff --git a/spec/models/agents/data_output_agent_spec.rb b/spec/models/agents/data_output_agent_spec.rb index daff36e534..e6e68fffdd 100644 --- a/spec/models/agents/data_output_agent_spec.rb +++ b/spec/models/agents/data_output_agent_spec.rb @@ -150,7 +150,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') expect(content.gsub(/\s+/, '')).to eq Utils.unindent(<<-XML).gsub(/\s+/, '') @@ -193,12 +193,25 @@ XML end + describe "with cumstom rss_content_type given" do + before do + agent.options['rss_content_type'] = 'text/xml' + agent.save! + end + + it "can output RSS with the Content-Type" do + content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') + expect(status).to eq(200) + expect(content_type).to eq('text/xml') + end + end + it "can output RSS with hub links when push_hubs is specified" do stub(agent).feed_link { "https://yoursite.com" } agent.options[:push_hubs] = %w[https://pubsubhubbub.superfeedr.com/ https://pubsubhubbub.appspot.com/] content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') xml = Nokogiri::XML(content) expect(xml.xpath('/rss/channel/atom:link[@rel="hub"]/@href').map(&:text).sort).to eq agent.options[:push_hubs].sort end @@ -314,7 +327,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') expect(Nokogiri(content).at('/rss/channel/title/text()').text).to eq('XKCD comics as a feed (XKCD)') end @@ -358,7 +371,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') expect(Nokogiri(content).at('/rss/channel/atom:icon/text()').text).to eq('https://somesite.com/icon.png') end end @@ -373,7 +386,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') doc = Nokogiri(content) namespaces = doc.collect_namespaces @@ -391,7 +404,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') doc = Nokogiri(content) namespaces = doc.collect_namespaces @@ -411,7 +424,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') doc = Nokogiri(content) namespaces = doc.collect_namespaces @@ -429,7 +442,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') doc = Nokogiri(content) namespaces = doc.collect_namespaces @@ -447,7 +460,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') doc = Nokogiri(content) namespaces = doc.collect_namespaces @@ -467,7 +480,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') doc = Nokogiri(content) namespaces = doc.collect_namespaces @@ -569,7 +582,7 @@ stub(agent).feed_link { "https://yoursite.com" } content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml') expect(status).to eq(200) - expect(content_type).to eq('text/xml') + expect(content_type).to eq('application/rss+xml') expect(content.gsub(/\s+/, '')).to eq Utils.unindent(<<-XML).gsub(/\s+/, '')