From 1fb0b424ed62a38120419abec93050fce6fc540a Mon Sep 17 00:00:00 2001
From: Chris Hunt <c@chrishunt.co>
Date: Mon, 10 Jun 2013 09:27:13 -0700
Subject: [PATCH] Add Stack Exchange onebox

---
 app/assets/images/favicons/stackexchange.png  | Bin 0 -> 1438 bytes
 lib/oneboxer/stack_exchange_onebox.rb         |  46 ++++++++++++++++
 .../templates/stack_exchange_onebox.hbrs      |  38 +++++++++++++
 .../oneboxer/stack_exchange_onebox_spec.rb    |  52 ++++++++++++++++++
 4 files changed, 136 insertions(+)
 create mode 100644 app/assets/images/favicons/stackexchange.png
 create mode 100644 lib/oneboxer/stack_exchange_onebox.rb
 create mode 100644 lib/oneboxer/templates/stack_exchange_onebox.hbrs
 create mode 100644 spec/components/oneboxer/stack_exchange_onebox_spec.rb

diff --git a/app/assets/images/favicons/stackexchange.png b/app/assets/images/favicons/stackexchange.png
new file mode 100644
index 0000000000000000000000000000000000000000..91e4dbbe4b5f9d11f558519529db543ba59d1ffd
GIT binary patch
literal 1438
zcmV;P1!4M$P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV000CeX+uL$Nkc;*
zP;zf(X>4Tx05}naRo`#hR1`jmZ&IWdKOk5~hl<6oRa0BJ8yc;~21%2p?MfD<>DVeH
z<T^KrsT&8|>9(p*dx19w`~g7O0}n_%Aq@s%d)fBDv`JHkDym6Hd+5XuAtvnwRpGmK
zVkc9?T=n|PIo~<wJLg{8L_J?=wVD}Kh?c9aozEndlcyGxo=u9<v(!ri)T`-EEs@L3
z5-!0N_s;9#9f}Cc?UC;OPWB_edW+oAi6T$HZWSGU8TbrQ%+zbPOBBBc`}k?M2Hf);
z@Y6N~0;>X-eVh__(Z?q}P9Z-Dj?gOW6|D%o20XmjW-qs4UjrD(li^iv8@eK9k+ZFm
zVRFymFOPAzG5-%Pn|1W;U4vNroTa&AxDScmEA~{ri9gr1^c?U@uwSpaNnw8l_>cP1
zd;)kMQS_;jeRSUEM_*s96y65j1$)tOrwdK{YIQMt92l|D^(E_=$Rjw{b!QT@q!)ni
zR`|5oW9X5n$Wv+HVc@|^eX5yXnsHX<gx$-tTA9oOBadXir_JPm2Y^4ct-PoO&C)tI
zGolvqOIK@duBk!Vu9{g<3;i;gJ6?~-DQ&xz!jvD&4!U-s8Os(*#?k2}f30SEXA#=i
z1-qUX+K`{!((H5w7<t$~ygD!D1{~X6)KX%$qrgY#L_{M_7A<1csY*MfP@XcB#Jxr~
zJS8&7goVS)VKE|4(h_Xlc{z{c$ApZs7riZ_QKdV_uW-M~u~<J-*#Z0?VzcZp8)p-w
zus7J7><CN2I>8PF3UX~a6)MwxDE0HaPjyrlI!;jX{6Kvuh*8ej?;85ekN$?5uuCiS
zBTvvVG+XTxAO{m@bvM#Jr)z6J><&E22D|vq?Y?Vkbo_DijopiF$2PET#<s%v*srlI
z{B2SKJ79W>mZ8e<cESmGBON_l0n;T7>u=y$(ArYkv7@Ex`GL?QCc!_*KFrd&;n1r7
zqW-CFs9&fT)ZaU5gc&=gBz-D<EBz>aCw(vdOp0__x+47~U6sC(E(JNe@4cTT*n6*E
zVH4eoU1-&7pEV~_PRe`a7v+@vy!^5}8?Y3)UmlaE<h}6h3HHql{T;m+bPBU-O|^S1
z@dOw&4<!bj2G_<^#e}PL7FpY$lcrKO$i~?8Bd2y;oaL5^csibnCrF9!i%-PI;xhub
zp1k;8_$IKX1NHus6EHeD;B72SCCD@4ojP$=Mf3`Eo6yZ&eg@wTqDiZE);7u&SJ|(s
zuPF(9%D6IJ)klXF%`_Fy<tR3HxV^%Qqa?nAB97=m-uu2qcHInZ?ps8M|H3=#R%lzO
z6MgLv^}ib0hVV{&<};#;2lcwW;^(7C<OY#bI<VjS9qCKr-E_Cnc!2j+&nHAXA2%BR
zt~VMxUn2h&(Pi^LSpac(Y#S>R0003sNkl<ZI1yv~|NlP&2s9ozz#=T7mBPrxC<qq7
zLHz&s|NYxH*XGnaIQ#)AVS%X=71!Rt%FN^q<Kv@Qh18va@}VF#OfZG4j7+XDHa`08
zkKYXMzWsq)#0c{OK27-K;9f}H{0R~mI8;CV@Q2~qhktO{OSvM9AP(FMa2YHNbj`?0
zsON>iwksH3c>LlA!?Ty)ku8L?pRKgT?*)9C;ido?)boOW{?aGR%*@h{pS@#v`s_Wj
zB^d1g4FA9UefL-L)s^}$@K|7EWMn5sGsHAT&Yye?Y#=r~9o&ENHtE%?Pc=Y4F(a&G
z<Yr)GPz3VX5n}&uGyZ36{&=kZ9Y~B|7)aT*B4X#?zszSxYG)t}BQhZYllvzi&Oz4<
sG6?PkWK%KN|NmP(KT>-YLmVgo07mG4yve3Ke*gdg07*qoM6N<$f<ceFC;$Ke

literal 0
HcmV?d00001

diff --git a/lib/oneboxer/stack_exchange_onebox.rb b/lib/oneboxer/stack_exchange_onebox.rb
new file mode 100644
index 000000000..0a1f42f72
--- /dev/null
+++ b/lib/oneboxer/stack_exchange_onebox.rb
@@ -0,0 +1,46 @@
+require_dependency 'oneboxer/handlebars_onebox'
+
+module Oneboxer
+  class StackExchangeOnebox < HandlebarsOnebox
+    DOMAINS = [
+      'stackexchange',
+      'stackoverflow',
+      'superuser',
+      'serverfault',
+      'askubuntu'
+    ]
+
+    # http://rubular.com/r/V3T0I1VTPn
+    REGEX =
+      /^http:\/\/(?:(?<subdomain>\w*)\.)?(?<domain>#{DOMAINS.join('|')})\.com\/(?:questions|q)\/(?<question>\d*)/
+
+    matcher REGEX
+    favicon 'stackexchange.png'
+
+    def translate_url
+      @url.match(REGEX) do |match|
+        site = if match[:domain] == 'stackexchange'
+          match[:subdomain]
+        else
+          match[:domain]
+        end
+
+        ["http://api.stackexchange.com/2.1/",
+         "questions/#{match[:question]}",
+         "?site=#{site}"
+        ].join
+      end
+    end
+
+    def parse(data)
+      result = JSON.parse(data)['items'].first
+
+      result['creation_date'] =
+        Time.at(result['creation_date'].to_i).strftime("%I:%M%p - %d %b %y")
+
+      result['tags'] = result['tags'].take(4).join(', ')
+
+      result
+    end
+  end
+end
diff --git a/lib/oneboxer/templates/stack_exchange_onebox.hbrs b/lib/oneboxer/templates/stack_exchange_onebox.hbrs
new file mode 100644
index 000000000..57d5946e4
--- /dev/null
+++ b/lib/oneboxer/templates/stack_exchange_onebox.hbrs
@@ -0,0 +1,38 @@
+<div class="onebox-result">
+  {{#host}}
+    <div class="source">
+      <div class="info">
+        <a href="{{link}}" class="track-link" target="_blank">
+          {{#favicon}}
+            <img class="favicon" src="{{favicon}}">
+          {{/favicon}}
+          {{host}}
+        </a>
+      </div>
+    </div>
+  {{/host}}
+
+  <div class="onebox-result-body">
+    {{#owner.profile_image}}
+      <a href="{{owner.link}}" target="_blank">
+        <img alt="{{owner.display_name}}" src="{{owner.profile_image}}">
+      </a>
+    {{/owner.profile_image}}
+
+    <h4>
+      <a href="{{link}}" target="_blank">{{{title}}}</a>
+    </h4>
+
+    <div class="date">
+      asked by <a href="{{owner.link}}" target="_blank">
+        {{owner.display_name}}
+      </a>
+      on <a href="{{link}}" target="_blank">{{creation_date}}</a>
+    </div>
+
+    <div>
+      <strong>{{tags}}</strong>
+    </div>
+  </div>
+  <div class="clearfix"></div>
+</div>
diff --git a/spec/components/oneboxer/stack_exchange_onebox_spec.rb b/spec/components/oneboxer/stack_exchange_onebox_spec.rb
new file mode 100644
index 000000000..3a4dbd9a7
--- /dev/null
+++ b/spec/components/oneboxer/stack_exchange_onebox_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe Oneboxer::StackExchangeOnebox do
+  describe '#translate_url' do
+    let(:question) { '15622543' }
+    let(:api_url) {
+      "http://api.stackexchange.com/2.1/questions/#{question}?site=#{site}"
+    }
+
+    context 'when the question is from Stack Overflow' do
+      let(:site) { 'stackoverflow' }
+
+      it 'returns the correct api url for an expanded url' do
+        onebox = described_class.new([
+          "http://#{site}.com/",
+          "questions/#{question}/discourse-ruby-2-0-rails-4"
+        ].join)
+
+        expect(onebox.translate_url).to eq api_url
+      end
+
+      it 'returns the correct api url for a share url' do
+        onebox = described_class.new("http://#{site}.com/q/#{question}")
+
+        expect(onebox.translate_url).to eq api_url
+      end
+    end
+
+    context 'when the question is from Super User' do
+      let(:site) { 'superuser' }
+
+      it 'returns the correct api url' do
+        onebox = described_class.new("http://#{site}.com/q/#{question}")
+
+        expect(onebox.translate_url).to eq api_url
+      end
+    end
+
+    context 'when the question is from a Stack Exchange subdomain' do
+      let(:site) { 'gamedev' }
+
+      it 'returns the correct api url' do
+        onebox = described_class.new([
+          "http://#{site}.stackexchange.com/",
+          "questions/#{question}/how-to-prevent-the-too-awesome-to-use-syndrome"
+        ].join)
+
+        expect(onebox.translate_url).to eq api_url
+      end
+    end
+  end
+end