diff --git a/lib/onebox/engine.rb b/lib/onebox/engine.rb index 99064c64b37..5d64fa41f6d 100644 --- a/lib/onebox/engine.rb +++ b/lib/onebox/engine.rb @@ -210,3 +210,4 @@ require_relative "engine/kaltura_onebox" require_relative "engine/reddit_media_onebox" require_relative "engine/google_drive_onebox" require_relative "engine/facebook_media_onebox" +require_relative "engine/hackernews_onebox" diff --git a/lib/onebox/engine/hackernews_onebox.rb b/lib/onebox/engine/hackernews_onebox.rb new file mode 100644 index 00000000000..79d8e037a58 --- /dev/null +++ b/lib/onebox/engine/hackernews_onebox.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Onebox + module Engine + class HackernewsOnebox + include Engine + include LayoutSupport + include JSON + + REGEX = /^https?:\/\/news\.ycombinator\.com\/item\?id=(?\d+)/ + + matches_regexp(REGEX) + + # This is their official API: https://blog.ycombinator.com/hacker-news-api/ + def url + "https://hacker-news.firebaseio.com/v0/item/#{match[:item_id]}.json" + end + + private + + def match + @match ||= @url.match(REGEX) + end + + def data + return nil unless %w{story comment}.include?(raw['type']) + + html_entities = HTMLEntities.new + data = { + link: @url, + title: Onebox::Helpers.truncate(raw['title'], 80), + favicon: 'https://news.ycombinator.com/y18.gif', + timestamp: Time.at(raw['time']).strftime("%-l:%M %p - %-d %b %Y"), + author: raw['by'] + } + + data['description'] = html_entities.decode(Onebox::Helpers.truncate(raw['text'], 400)) if raw['text'] + + if raw['type'] == 'story' + data['data_1'] = raw['score'] + data['data_2'] = raw['descendants'] + end + + data + end + end + end +end diff --git a/lib/onebox/templates/hackernews.mustache b/lib/onebox/templates/hackernews.mustache new file mode 100644 index 00000000000..e4431a26016 --- /dev/null +++ b/lib/onebox/templates/hackernews.mustache @@ -0,0 +1,18 @@ +

{{title}}

+ +{{#description}} +

{{description}}

+{{/description}} + + +

+ {{#data_1}} + {{data_1}} points — + {{/data_1}} + {{#data_2}} + {{data_2}} comments — + {{/data_2}} + {{author}} — + {{timestamp}} +

+ diff --git a/spec/fixtures/onebox/hackernews_comment.response b/spec/fixtures/onebox/hackernews_comment.response new file mode 100644 index 00000000000..93c753faefb --- /dev/null +++ b/spec/fixtures/onebox/hackernews_comment.response @@ -0,0 +1 @@ +{"by":"codinghorror","id":5173615,"parent":5173013,"text":"Completely, forums are about basic human expression in paragraph form. This is an essential right and we want to give it back to the world in 100% no strings attached open source form.

Not that there aren't other forum choices, of course there are, but VERY few are 100% open source and even fewer are ones I want to use.","time":1360102194,"type":"comment"} \ No newline at end of file diff --git a/spec/fixtures/onebox/hackernews_story.response b/spec/fixtures/onebox/hackernews_story.response new file mode 100644 index 00000000000..2896cdeece9 --- /dev/null +++ b/spec/fixtures/onebox/hackernews_story.response @@ -0,0 +1 @@ +{"by":"sosuke","descendants":270,"id":5172905,"kids":[5173142,5173462,5173017,5173011,5173162,5173096,5173389,5173293,5173674,5173185,5173184,5173102,5176942,5173013,5173470,5173134,5174761,5173633,5173075,5173367,5173441,5172994,5172963,5173100,5173129,5173922,5173532,5175377,5173063,5173118,5174902,5173062,5173188,5173217,5174393,5173283,5173595,5175282,5174673,5173220,5173987,5174254,5174114,5173433,5172970,5174863,5173152,5173268,5174226,5173925,5174224,5173045,5174240,5173307,5174395,5175680,5174795,5174098,5175464,5175574,5173095,5179521,5173072,5173511,5175643,5176315,5173012,5173054,5173512,5175604,5173042,5173608,5172961,5177654,5178409,5174238,5173099,5174201,5173081,5175087,5174260,5173820,5174730],"score":727,"time":1360094559,"title":"Civilized Discourse Construction Kit","type":"story","url":"http://www.codinghorror.com/blog/2013/02/civilized-discourse-construction-kit.html"} \ No newline at end of file diff --git a/spec/lib/onebox/engine/hackernews_spec.rb b/spec/lib/onebox/engine/hackernews_spec.rb new file mode 100644 index 00000000000..539019b9d0e --- /dev/null +++ b/spec/lib/onebox/engine/hackernews_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require "rails_helper" + +describe Onebox::Engine::HackernewsOnebox do + context "When oneboxing a comment" do + let(:link) { "https://news.ycombinator.com/item?id=30181167" } + let(:api_link) { "https://hacker-news.firebaseio.com/v0/item/30181167.json" } + let(:html) { described_class.new(link).to_html } + + before do + stub_request(:get, api_link).to_return(status: 200, body: onebox_response("hackernews_comment")) + end + + it "has the comments first words" do + expect(html).to include("Completely, forums are about basic human expression in paragraph form.") + end + + it "has author username" do + expect(html).to include("codinghorror") + end + + it "has the permalink to the comic" do + expect(html).to include(link) + end + + it "has the item date" do + expect(html).to include("2013") + end + end + + context "When oneboxing a story" do + let(:link) { "https://news.ycombinator.com/item?id=5172905" } + let(:api_link) { "https://hacker-news.firebaseio.com/v0/item/5172905.json" } + let(:html) { described_class.new(link).to_html } + + before do + stub_request(:get, api_link).to_return(status: 200, body: onebox_response("hackernews_story")) + end + + it "has story title" do + expect(html).to include("Civilized Discourse Construction Kit") + end + + it "has author username" do + expect(html).to include("sosuke") + end + + it "has the permalink to the comic" do + expect(html).to include(link) + end + + it "has the item date" do + expect(html).to include("2013") + end + end +end