Skip to content

Commit

Permalink
Merge pull request #6941 from fjordllc/bug/save-rss-with-no-publish-date
Browse files Browse the repository at this point in the history
記事ごとの登録日時を持たない場合も例外が発生しないよう修正
  • Loading branch information
komagata authored Dec 5, 2023
2 parents 83d7613 + b87df79 commit fe0a7c3
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 24 deletions.
67 changes: 49 additions & 18 deletions app/models/external_entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class << self
def fetch_and_save_rss_feeds(users)
threads = Concurrent::Promises.future do
users.each do |user|
rss_items = ExternalEntry.parse_rss_feed(user.feed_url)
feed = ExternalEntry.parse_rss_feed(user.feed_url)

next unless rss_items
next unless feed

rss_items.each do |item|
feed.items.each do |item|
case item.class.name
when 'RSS::Atom::Feed::Entry' then ExternalEntry.save_atom_feed(user, item)
when 'RSS::Rss::Channel::Item' then ExternalEntry.save_rss_feed(user, item)
when 'RSS::RDF::Item' then ExternalEntry.save_rdf_feed(user, item)
when 'RSS::Atom::Feed::Entry' then ExternalEntry.save_atom_feed(user, item, feed.updated&.content)
when 'RSS::Rss::Channel::Item' then ExternalEntry.save_rss_feed(user, item, feed.channel&.lastBuildDate)
when 'RSS::RDF::Item' then ExternalEntry.save_rdf_feed(user, item, feed.channel&.dc_date)
end
end
end
Expand All @@ -38,50 +38,81 @@ def parse_rss_feed(feed_url)
return nil if feed_url.blank?

begin
RSS::Parser.parse(feed_url).items
RSS::Parser.parse(feed_url)
rescue StandardError => e
logger.warn("[RSS Feed] #{feed_url}: #{e.message}")
nil
end
end

def save_rdf_feed(user, rdf_item)
def save_rdf_feed(user, rdf_item, feed_updated)
return if ExternalEntry.find_by(url: rdf_item.link)

published_at = rdf_publish_date(rdf_item, feed_updated)
ExternalEntry.create(
title: rdf_item.title,
url: rdf_item.link,
summary: rdf_item.description,
thumbnail_image_url: nil,
published_at: rdf_item.dc_date,
published_at: published_at.utc? ? Time.zone.parse(published_at.to_s) : published_at,
user:
)
end

def save_rss_feed(user, rss_item)
def save_rss_feed(user, rss_item, feed_updated)
return if ExternalEntry.find_by(url: rss_item.link)

published_at = rss_publish_date(rss_item, feed_updated)
ExternalEntry.create(
title: rss_item.title,
url: rss_item.link,
summary: rss_item.description,
thumbnail_image_url: rss_item.enclosure&.url,
published_at: rss_item.pubDate,
published_at: published_at.utc? ? Time.zone.parse(published_at.to_s) : published_at,
user:
)
end

def save_atom_feed(user, atom_item)
return if ExternalEntry.find_by(url: atom_item.link.href)
def save_atom_feed(user, atom_item, feed_updated)
return if ExternalEntry.find_by(url: atom_item.link&.href)

published_at = atom_publish_date(atom_item, feed_updated)
ExternalEntry.create(
title: atom_item.title.content,
url: atom_item.link.href,
summary: atom_item.content.content,
thumbnail_image_url: atom_item.links.find { |link| !link.type.nil? && link.type.include?('image') }&.href,
published_at: atom_item.published.content,
title: atom_item.title&.content,
url: atom_item.link&.href,
summary: atom_item.content&.content,
thumbnail_image_url: atom_image_url(atom_item),
published_at: published_at.utc? ? Time.zone.parse(published_at.to_s) : published_at,
user:
)
end

private

def rdf_publish_date(rdf_item, feed_updated)
return rdf_item.dc_date if rdf_item.dc_date
return feed_updated if feed_updated

Time.zone.now
end

def rss_publish_date(rss_item, feed_updated)
return rss_item.pubDate if rss_item.pubDate
return feed_updated if feed_updated

Time.zone.now
end

def atom_image_url(atom_item)
atom_item.links&.find { |link| !link.type.nil? && link.type.include?('image') }&.href
end

def atom_publish_date(atom_item, feed_updated)
return atom_item.published.content if atom_item.published
return atom_item.updated.content if atom_item.updated
return feed_updated if feed_updated

Time.zone.now
end
end
end
101 changes: 95 additions & 6 deletions test/models/external_entry_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,84 @@ class ExternalEntryTest < ActiveSupport::TestCase
rdf_item.expect(:link, 'https://test.com/index.rdf')
rdf_item.expect(:description, 'article description')
rdf_item.expect(:dc_date, Time.zone.local(2022, 1, 1, 0, 0, 0))
rdf_item.expect(:dc_date, Time.zone.local(2022, 1, 1, 0, 0, 0))

assert ExternalEntry.save_rdf_feed(user, rdf_item, nil)
end

test '.save_rdf_feed with no article publish date' do
user = users(:hatsuno)
rdf_item = Minitest::Mock.new
rdf_item.expect(:link, 'https://test.com/index.rdf')
rdf_item.expect(:title, 'test title')
rdf_item.expect(:link, 'https://test.com/index.rdf')
rdf_item.expect(:description, 'article description')
rdf_item.expect(:dc_date, nil)

assert ExternalEntry.save_rdf_feed(user, rdf_item, nil)
end

test '.save_rdf_feed no exception even if all rdf elements are nil' do
user = users(:hatsuno)
rdf_item = Minitest::Mock.new
rdf_item.expect(:link, nil)
rdf_item.expect(:title, nil)
rdf_item.expect(:link, nil)
rdf_item.expect(:description, nil)
rdf_item.expect(:dc_date, nil)

assert ExternalEntry.save_rdf_feed(user, rdf_item)
assert ExternalEntry.save_rdf_feed(user, rdf_item, Time.zone.local(2023, 1, 1, 0, 0, 0).utc)
end

test '.save_rss_feed' do
user = users(:hatsuno)
rss_item = Minitest::Mock.new
rss_item.expect(:link, 'https://test.com/rss')
rss_item.expect(:pubDate, Time.zone.local(2022, 1, 1, 0, 0, 0))
rss_item.expect(:pubDate, Time.zone.local(2022, 1, 1, 0, 0, 0))
rss_item.expect(:title, 'test title')
rss_item.expect(:link, 'https://test.com/rss')
rss_item.expect(:description, 'article description')
rss_item.expect(:enclosure, rss_item)
rss_item.expect(:url, 'https://test.com/image.png')
rss_item.expect(:pubDate, Time.zone.local(2022, 1, 1, 0, 0, 0))

assert ExternalEntry.save_rss_feed(user, rss_item)
assert ExternalEntry.save_rss_feed(user, rss_item, nil)
end

test '.save_rss_feed with no article publish date' do
user = users(:hatsuno)
rss_item = Minitest::Mock.new
rss_item.expect(:link, 'https://test.com/rss')
rss_item.expect(:pubDate, nil)
rss_item.expect(:title, 'test title')
rss_item.expect(:link, 'https://test.com/rss')
rss_item.expect(:description, 'article description')
rss_item.expect(:enclosure, nil)

assert ExternalEntry.save_rss_feed(user, rss_item, Time.zone.local(2023, 1, 1, 0, 0, 0).utc)
end

test '.save_rss_feed no exception even if all rss elements are nil' do
user = users(:hatsuno)
rss_item = Minitest::Mock.new
rss_item.expect(:link, nil)
rss_item.expect(:pubDate, nil)
rss_item.expect(:title, nil)
rss_item.expect(:link, nil)
rss_item.expect(:description, nil)
rss_item.expect(:enclosure, nil)

assert ExternalEntry.save_rss_feed(user, rss_item, nil)
end

test '.save_atom_feed' do
user = users(:hatsuno)
atom_item = Minitest::Mock.new
atom_item.expect(:link, atom_item)
atom_item.expect(:href, 'https://test.com/feed')
atom_item.expect(:published, atom_item)
atom_item.expect(:published, atom_item)
atom_item.expect(:content, Time.zone.local(2022, 1, 1, 0, 0, 0))
atom_item.expect(:title, atom_item)
atom_item.expect(:content, 'test title')
atom_item.expect(:link, atom_item)
Expand All @@ -65,10 +120,44 @@ class ExternalEntryTest < ActiveSupport::TestCase
atom_item.expect(:find, atom_item)
atom_item.expect(:nil?, atom_item)
atom_item.expect(:href, 'https://test.com/image.png')
atom_item.expect(:published, atom_item)
atom_item.expect(:content, Time.zone.local(2022, 1, 1, 0, 0, 0))

assert ExternalEntry.save_atom_feed(user, atom_item)
assert ExternalEntry.save_atom_feed(user, atom_item, nil)
end

test '.save_atom_feed with no article publish date' do
user = users(:hatsuno)
atom_item = Minitest::Mock.new
atom_item.expect(:link, atom_item)
atom_item.expect(:href, 'https://test.com/feed')
atom_item.expect(:published, nil)
atom_item.expect(:updated, nil)
atom_item.expect(:title, atom_item)
atom_item.expect(:content, 'test title')
atom_item.expect(:link, atom_item)
atom_item.expect(:href, 'https://test.com/feed')
atom_item.expect(:content, atom_item)
atom_item.expect(:content, 'article description')
atom_item.expect(:links, atom_item)
atom_item.expect(:find, atom_item)
atom_item.expect(:nil?, atom_item)
atom_item.expect(:href, 'https://test.com/image.png')

assert ExternalEntry.save_atom_feed(user, atom_item, Time.zone.local(2023, 1, 1, 0, 0, 0).utc)
end

test '.save_atom_feed no exception even if all atom elements are nil' do
user = users(:hatsuno)
atom_item = Minitest::Mock.new
atom_item.expect(:link, nil)
atom_item.expect(:published, nil)
atom_item.expect(:updated, nil)
atom_item.expect(:title, nil)
atom_item.expect(:content, nil)
atom_item.expect(:link, nil)
atom_item.expect(:content, nil)
atom_item.expect(:links, nil)

assert ExternalEntry.save_atom_feed(user, atom_item, nil)
end

test '.fetch_and_save_rss_feeds' do
Expand Down

0 comments on commit fe0a7c3

Please sign in to comment.