opengraph POC
Fixed small-frame opengraph view Fixed incompletely saved OpenGraphCache bug
This commit is contained in:
parent
9d6ac1abe5
commit
176c6826e0
19 changed files with 200 additions and 6 deletions
1
Gemfile
1
Gemfile
|
|
@ -64,6 +64,7 @@ gem 'rails_autolink', '1.1.0'
|
|||
gem 'redcarpet', '3.0.0'
|
||||
gem 'roxml', '3.1.6'
|
||||
gem 'ruby-oembed', '0.8.8'
|
||||
gem 'opengraph', '0.0.4'
|
||||
|
||||
|
||||
# Please remove when migrating to Rails 4
|
||||
|
|
|
|||
|
|
@ -249,6 +249,10 @@ GEM
|
|||
omniauth-twitter (1.0.0)
|
||||
multi_json (~> 1.3)
|
||||
omniauth-oauth (~> 1.0)
|
||||
opengraph (0.0.4)
|
||||
hashie
|
||||
nokogiri (~> 1.5.0)
|
||||
rest-client (~> 1.6.0)
|
||||
orm_adapter (0.4.0)
|
||||
polyglot (0.3.3)
|
||||
pry (0.9.12.2)
|
||||
|
|
@ -322,6 +326,8 @@ GEM
|
|||
redis-namespace (1.3.0)
|
||||
redis (~> 3.0.0)
|
||||
remotipart (1.2.1)
|
||||
rest-client (1.6.7)
|
||||
mime-types (>= 1.16)
|
||||
rmagick (2.13.2)
|
||||
roxml (3.1.6)
|
||||
activesupport (>= 2.3.0)
|
||||
|
|
@ -464,6 +470,7 @@ DEPENDENCIES
|
|||
omniauth-facebook (= 1.4.1)
|
||||
omniauth-tumblr (= 1.1)
|
||||
omniauth-twitter (= 1.0.0)
|
||||
opengraph (= 0.0.4)
|
||||
rack-cors (= 0.2.8)
|
||||
rack-google-analytics (= 0.11.0)
|
||||
rack-piwik (= 0.2.2)
|
||||
|
|
|
|||
8
app/assets/javascripts/app/helpers/open_graph.js
Normal file
8
app/assets/javascripts/app/helpers/open_graph.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
(function(){
|
||||
app.helpers.openGraph = {
|
||||
html : function (open_graph_cache) {
|
||||
if (!open_graph_cache) { return "" }
|
||||
return '<img src="' + open_graph_cache.image + '" />'
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -44,9 +44,13 @@ app.views.Content = app.views.Base.extend({
|
|||
var collHeight = 200
|
||||
, elem = this.$(".collapsible")
|
||||
, oembed = elem.find(".oembed")
|
||||
, opengraph = elem.find(".opengraph")
|
||||
, addHeight = 0;
|
||||
if($.trim(oembed.html()) != "") {
|
||||
addHeight = oembed.height();
|
||||
addHeight += oembed.height();
|
||||
}
|
||||
if($.trim(opengraph.html()) != "") {
|
||||
addHeight += opengraph.height();
|
||||
}
|
||||
|
||||
// only collapse if height exceeds collHeight+20%
|
||||
|
|
@ -102,3 +106,7 @@ app.views.OEmbed = app.views.Base.extend({
|
|||
this.$el.html(insertHTML);
|
||||
}
|
||||
});
|
||||
|
||||
app.views.OpenGraph = app.views.Base.extend({
|
||||
templateName : "opengraph"
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ app.views.Post.SmallFrame = app.views.Post.extend({
|
|||
},
|
||||
|
||||
subviews : {
|
||||
'.embed-frame' : "oEmbedView"
|
||||
'.embed-frame' : "oEmbedView",
|
||||
'.open-graph-frame' : 'openGraphView'
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
|
|
@ -22,6 +23,10 @@ app.views.Post.SmallFrame = app.views.Post.extend({
|
|||
return new app.views.OEmbed({model : this.model})
|
||||
},
|
||||
|
||||
openGraphView : function(){
|
||||
return new app.views.OpenGraph({model : this.model})
|
||||
},
|
||||
|
||||
smallFramePresenter : function(){
|
||||
//todo : we need to have something better for small frame text, probably using the headline() scenario.
|
||||
return _.extend(this.defaultPresenter(),
|
||||
|
|
@ -50,10 +55,10 @@ app.views.Post.SmallFrame = app.views.Post.extend({
|
|||
var text = this.model.get("text")
|
||||
, baseClass = $.trim(text).length == 0 ? "no-text" : "has-text";
|
||||
|
||||
if(this.model.get("photos").length > 0 || this.model.get("o_embed_cache"))
|
||||
if(this.model.get("photos").length > 0 || this.model.get("o_embed_cache") || this.model.get("open_graph_cache"))
|
||||
baseClass += " has-media";
|
||||
|
||||
if(baseClass == "no-text" || this.model.get("photos").length > 0 || this.model.get("o_embed_cache")) { return baseClass }
|
||||
if(baseClass == "no-text" || this.model.get("photos").length > 0 || this.model.get("o_embed_cache") || this.model.get("open_graph_cache")) { return baseClass }
|
||||
|
||||
var randomColor = _.first(_.shuffle(['cyan', 'green', 'yellow', 'purple', 'lime-green', 'orange', 'red', 'turquoise', 'sand']));
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ app.views.StreamPost = app.views.Post.extend({
|
|||
".comments" : "commentStreamView",
|
||||
".post-content" : "postContentView",
|
||||
".oembed" : "oEmbedView",
|
||||
".opengraph" : "openGraphView",
|
||||
".status-message-location" : "postLocationStreamView"
|
||||
},
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ app.views.StreamPost = app.views.Post.extend({
|
|||
//subviews
|
||||
this.commentStreamView = new app.views.CommentStream({model : this.model});
|
||||
this.oEmbedView = new app.views.OEmbed({model : this.model});
|
||||
this.openGraphView = new app.views.OpenGraph({model : this.model});
|
||||
},
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1953,6 +1953,23 @@ ul#press_logos
|
|||
iframe, .thumb img
|
||||
:width 100%
|
||||
|
||||
.opengraph
|
||||
:float left
|
||||
:width 100%
|
||||
a
|
||||
:display block
|
||||
:text-decoration none
|
||||
:color #000
|
||||
:margin-top 10px
|
||||
:border-top solid 1px #DDD
|
||||
:border-bottom solid 1px #DDD
|
||||
:padding 10px 0px 10px 0px
|
||||
|
||||
img
|
||||
:margin 10px 0px 10px 0px
|
||||
:float left
|
||||
br
|
||||
:clear both
|
||||
|
||||
.conversation_participants
|
||||
:background
|
||||
|
|
|
|||
10
app/assets/templates/opengraph_tpl.jst.hbs
Normal file
10
app/assets/templates/opengraph_tpl.jst.hbs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{{#if open_graph_cache}}
|
||||
<a href="{{open_graph_cache.url}}" target="_blank">
|
||||
<div>
|
||||
<h3>{{open_graph_cache.title}}</h3>
|
||||
<img src="{{open_graph_cache.image}}" />
|
||||
<p>{{open_graph_cache.description}}</p>
|
||||
<br />
|
||||
</div>
|
||||
</a>
|
||||
{{/if}}
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
{{/if}}
|
||||
|
||||
<div class="embed-frame" />
|
||||
<div class="open-graph-frame" />
|
||||
|
||||
{{#if text}}
|
||||
<div class="text-content">
|
||||
|
|
|
|||
|
|
@ -17,4 +17,5 @@
|
|||
<div class="collapsible">
|
||||
{{{text}}}
|
||||
<div class="oembed"></div>
|
||||
<div class="opengraph"></div>
|
||||
</div>
|
||||
|
|
@ -44,6 +44,25 @@ module OpenGraphHelper
|
|||
content_tag(:meta, '', :property => name, :content => content)
|
||||
end
|
||||
|
||||
def og_html(cache)
|
||||
title = cache.title
|
||||
html =
|
||||
"<div class=\"og-concent\">" +
|
||||
"<a class=\"og-link\" href=\"#{cache.url}\">" +
|
||||
"<img class=\"og-image\" src=\"#{cache.image}\"/>"
|
||||
"<h1 class=\"og-title\">#{cache.title}</h1>" +
|
||||
"<p class=\"og-description\">#{cache.description}</p>"
|
||||
"</a></div>"
|
||||
return html
|
||||
end
|
||||
|
||||
def link_to_oembed_image(cache, prefix = 'thumbnail_')
|
||||
link_to(oembed_image_tag(cache, prefix), cache.url, :target => '_blank')
|
||||
end
|
||||
|
||||
def oembed_image_tag(cache, prefix)
|
||||
image_tag(cache.data[prefix + 'url'], cache.options_hash(prefix))
|
||||
end
|
||||
private
|
||||
|
||||
# This method compensates for hosting assets off of s3
|
||||
|
|
|
|||
49
app/models/open_graph_cache.rb
Normal file
49
app/models/open_graph_cache.rb
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
class OpenGraphCache < ActiveRecord::Base
|
||||
attr_accessible :title
|
||||
attr_accessible :ob_type
|
||||
attr_accessible :image
|
||||
attr_accessible :url
|
||||
attr_accessible :description
|
||||
|
||||
validates :title, :presence => true
|
||||
validates :ob_type, :presence => true
|
||||
validates :image, :presence => true
|
||||
validates :url, :presence => true
|
||||
|
||||
has_many :posts
|
||||
|
||||
acts_as_api
|
||||
api_accessible :backbone do |t|
|
||||
t.add :title
|
||||
t.add :ob_type
|
||||
t.add :image
|
||||
t.add :description
|
||||
t.add :url
|
||||
end
|
||||
|
||||
def self.find_or_create_by_url(url)
|
||||
cache = OpenGraphCache.find_or_initialize_by_url(url)
|
||||
return cache if cache.persisted?
|
||||
cache.fetch_and_save_opengraph_data!
|
||||
return cache if cache.persisted?
|
||||
return nil
|
||||
end
|
||||
|
||||
def fetch_and_save_opengraph_data!
|
||||
begin
|
||||
response = OpenGraph.fetch(self.url)
|
||||
if !response
|
||||
return
|
||||
end
|
||||
rescue => e
|
||||
# noop
|
||||
else
|
||||
self.title = response.title
|
||||
self.ob_type = response.type
|
||||
self.image = response.image
|
||||
self.url = response.url
|
||||
self.description = response.description
|
||||
self.save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -24,13 +24,14 @@ class Post < ActiveRecord::Base
|
|||
has_many :resharers, :class_name => 'Person', :through => :reshares, :source => :author
|
||||
|
||||
belongs_to :o_embed_cache
|
||||
belongs_to :open_graph_cache
|
||||
|
||||
after_create do
|
||||
self.touch(:interacted_at)
|
||||
end
|
||||
|
||||
#scopes
|
||||
scope :includes_for_a_stream, includes(:o_embed_cache, {:author => :profile}, :mentions => {:person => :profile}) #note should include root and photos, but i think those are both on status_message
|
||||
scope :includes_for_a_stream, includes(:o_embed_cache, :open_graph_cache, {:author => :profile}, :mentions => {:person => :profile}) #note should include root and photos, but i think those are both on status_message
|
||||
|
||||
|
||||
scope :commented_by, lambda { |person|
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ class Reshare < Post
|
|||
self.root ? root.o_embed_cache : super
|
||||
end
|
||||
|
||||
def open_graph_cache
|
||||
self.root ? root.open_graph_cache : super
|
||||
end
|
||||
|
||||
def raw_message
|
||||
self.root ? root.raw_message : super
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,10 +26,12 @@ class StatusMessage < Post
|
|||
before_destroy :presence_of_content
|
||||
|
||||
attr_accessor :oembed_url
|
||||
attr_accessor :open_graph_url
|
||||
|
||||
before_create :filter_mentions
|
||||
after_create :create_mentions
|
||||
after_create :queue_gather_oembed_data, :if => :contains_oembed_url_in_text?
|
||||
after_create :queue_gather_open_graph_data, :if => :contains_open_graph_url_in_text?
|
||||
|
||||
#scopes
|
||||
scope :where_person_is_mentioned, lambda { |person|
|
||||
|
|
@ -143,11 +145,19 @@ class StatusMessage < Post
|
|||
Workers::GatherOEmbedData.perform_async(self.id, self.oembed_url)
|
||||
end
|
||||
|
||||
def queue_gather_open_graph_data
|
||||
Workers::GatherOpenGraphData.perform_async(self.id, self.open_graph_url)
|
||||
end
|
||||
|
||||
def contains_oembed_url_in_text?
|
||||
urls = URI.extract(self.raw_message, ['http', 'https'])
|
||||
self.oembed_url = urls.find{ |url| !TRUSTED_OEMBED_PROVIDERS.find(url).nil? }
|
||||
end
|
||||
|
||||
def contains_open_graph_url_in_text?
|
||||
self.open_graph_url = URI.extract(self.raw_message, ['http', 'https'])[0]
|
||||
end
|
||||
|
||||
def address
|
||||
location.try(:address)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class PostPresenter
|
|||
:nsfw => @post.nsfw,
|
||||
:author => @post.author.as_api_response(:backbone),
|
||||
:o_embed_cache => @post.o_embed_cache.try(:as_api_response, :backbone),
|
||||
:open_graph_cache => @post.open_graph_cache.try(:as_api_response, :backbone),
|
||||
:mentioned_people => @post.mentioned_people.as_api_response(:backbone),
|
||||
:photos => @post.photos.map {|p| p.as_api_response(:backbone)},
|
||||
:frame_name => @post.frame_name || template_name,
|
||||
|
|
|
|||
22
app/workers/gather_open_graph_data.rb
Normal file
22
app/workers/gather_open_graph_data.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
#
|
||||
|
||||
module Workers
|
||||
class GatherOpenGraphData < Base
|
||||
sidekiq_options queue: :http_service
|
||||
|
||||
def perform(post_id, url, retry_count=1)
|
||||
post = Post.find(post_id)
|
||||
post.open_graph_cache = OpenGraphCache.find_or_create_by_url(url)
|
||||
post.save
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
# User created a post and deleted it right afterwards before we
|
||||
# we had a chance to run the job.
|
||||
# On the other hand sometimes the job runs before the Post is
|
||||
# fully persisted. So we just reduce the amount of retries.
|
||||
GatherOpenGraphData.perform_in(1.minute, post_id, url, retry_count+1) unless retry_count > 3
|
||||
end
|
||||
end
|
||||
end
|
||||
19
db/migrate/20130608171134_add_open_graph_cache.rb
Normal file
19
db/migrate/20130608171134_add_open_graph_cache.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
class AddOpenGraphCache < ActiveRecord::Migration
|
||||
def up
|
||||
create_table :open_graph_caches do |t|
|
||||
t.string :title
|
||||
t.string :ob_type
|
||||
t.string :image
|
||||
t.string :url
|
||||
t.text :description
|
||||
end
|
||||
change_table :posts do |t|
|
||||
t.integer :open_graph_cache_id
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :posts, :open_graph_cache_id
|
||||
drop_table :open_graph_caches
|
||||
end
|
||||
end
|
||||
|
|
@ -215,6 +215,14 @@ ActiveRecord::Schema.define(:version => 20130801063213) do
|
|||
|
||||
add_index "o_embed_caches", ["url"], :name => "index_o_embed_caches_on_url", :length => {"url"=>255}
|
||||
|
||||
create_table "open_graph_caches", :force => true do |t|
|
||||
t.string "title"
|
||||
t.string "ob_type"
|
||||
t.string "image"
|
||||
t.string "url"
|
||||
t.text "description"
|
||||
end
|
||||
|
||||
create_table "participations", :force => true do |t|
|
||||
t.string "guid"
|
||||
t.integer "target_id"
|
||||
|
|
@ -309,6 +317,7 @@ ActiveRecord::Schema.define(:version => 20130801063213) do
|
|||
t.string "facebook_id"
|
||||
t.string "tweet_id"
|
||||
t.text "tumblr_ids"
|
||||
t.integer "open_graph_cache_id"
|
||||
end
|
||||
|
||||
add_index "posts", ["author_id", "root_guid"], :name => "index_posts_on_author_id_and_root_guid", :unique => true
|
||||
|
|
|
|||
Loading…
Reference in a new issue