Merge branch 'next-minor' into develop
This commit is contained in:
commit
a85c8e75f2
14 changed files with 231 additions and 44 deletions
|
|
@ -24,6 +24,7 @@
|
|||
## Features
|
||||
* Deleted comments will be removed when loading more comments [#7045](https://github.com/diaspora/diaspora/pull/7045)
|
||||
* The "subscribe" indicator on a post now gets toggled when you like or rehsare a post [#7040](https://github.com/diaspora/diaspora/pull/7040)
|
||||
* Add OpenGraph video support [#7043](https://github.com/diaspora/diaspora/pull/7043)
|
||||
|
||||
# 0.6.0.0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
(function(){
|
||||
app.helpers.openGraph = {
|
||||
html : function (open_graph_cache) {
|
||||
if (!open_graph_cache) { return ""; }
|
||||
return '<img src="' + open_graph_cache.image + '" />';
|
||||
},
|
||||
};
|
||||
})();
|
||||
// @license-end
|
||||
|
||||
|
|
@ -151,6 +151,10 @@ app.views.OEmbed = app.views.Base.extend({
|
|||
app.views.OpenGraph = app.views.Base.extend({
|
||||
templateName : "opengraph",
|
||||
|
||||
events: {
|
||||
"click .video-overlay": "loadVideo"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
this.truncateDescription();
|
||||
},
|
||||
|
|
@ -161,6 +165,12 @@ app.views.OpenGraph = app.views.Base.extend({
|
|||
var ogdesc = this.model.get('open_graph_cache');
|
||||
ogdesc.description = app.helpers.truncate(ogdesc.description, 250);
|
||||
}
|
||||
},
|
||||
|
||||
loadVideo: function() {
|
||||
this.$(".opengraph-container").html(
|
||||
"<iframe src='" + this.$(".video-overlay").attr("data-video-url") + "' frameBorder=0 width='100%'></iframe>"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -10,20 +10,41 @@
|
|||
overflow: hidden;
|
||||
a {
|
||||
color: #000;
|
||||
img {
|
||||
margin: 5px 5px 5px 0px;
|
||||
float: left;
|
||||
max-width: 150px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.og-title {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
a:hover {
|
||||
color: $blue;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
float: left;
|
||||
margin: 5px;
|
||||
margin-left: 0;
|
||||
max-width: 150px;
|
||||
padding-right: 5px;
|
||||
|
||||
.video-overlay {
|
||||
cursor: pointer;
|
||||
height: 145px;
|
||||
width: 145px;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
background-color: rgba($black, .2);
|
||||
background-image: image-url('buttons/playbtn.png');
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 60px 60px;
|
||||
display: inline-block;
|
||||
height: 145px;
|
||||
position: relative;
|
||||
top: -145px;
|
||||
width: 145px;
|
||||
}
|
||||
}
|
||||
|
||||
.og-description {
|
||||
color: $text-grey;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
{{#unless o_embed_cache}}
|
||||
{{#if open_graph_cache}}
|
||||
<div class="opengraph-container">
|
||||
<a href="{{open_graph_cache.url}}" target="_blank">
|
||||
<div class="thumb">
|
||||
{{#if open_graph_cache.video_url }}
|
||||
<div class="video-overlay" data-video-url="{{open_graph_cache.video_url}}">
|
||||
<img src="{{open_graph_cache.image}}" />
|
||||
<div class="overlay"></div>
|
||||
</div>
|
||||
{{else}}
|
||||
<img src="{{open_graph_cache.image}}" />
|
||||
{{/if}}
|
||||
</div>
|
||||
<a href="{{open_graph_cache.url}}" target="_blank">
|
||||
<p class="og-title">{{open_graph_cache.title}}</p>
|
||||
</a>
|
||||
<p class="og-description">{{open_graph_cache.description}}</p>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class OpenGraphCache < ActiveRecord::Base
|
|||
t.add :image
|
||||
t.add :description
|
||||
t.add :url
|
||||
t.add :video_url
|
||||
end
|
||||
|
||||
def image
|
||||
|
|
@ -39,8 +40,15 @@ class OpenGraphCache < ActiveRecord::Base
|
|||
self.image = object.og.image.url
|
||||
self.url = object.og.url
|
||||
self.description = object.og.description
|
||||
if object.og.video.try(:secure_url) && secure_video_url?(object.og.video.secure_url)
|
||||
self.video_url = object.og.video.secure_url
|
||||
end
|
||||
|
||||
self.save
|
||||
rescue OpenGraphReader::NoOpenGraphDataError, OpenGraphReader::InvalidObjectError
|
||||
end
|
||||
|
||||
def secure_video_url?(url)
|
||||
SECURE_OPENGRAPH_VIDEO_URLS.any? {|u| u =~ url }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,3 +5,18 @@ OpenGraphReader.configure do |config|
|
|||
config.synthesize_image_url = true
|
||||
config.guess_datetime_format = true
|
||||
end
|
||||
|
||||
og_video_urls = []
|
||||
og_providers = YAML.load_file(Rails.root.join("config", "open_graph_providers.yml"))
|
||||
og_providers.each do |_, provider|
|
||||
provider["video_urls"].each do |video_url|
|
||||
# taken from https://github.com/ruby-oembed/ruby-oembed/blob/fe2b63c/lib/oembed/provider.rb#L68
|
||||
_, scheme, domain, path = *video_url.match(%r{([^:]*)://?([^/?]*)(.*)})
|
||||
domain = Regexp.escape(domain).gsub("\\*", "(.*?)").gsub("(.*?)\\.", "([^\\.]+\\.)?")
|
||||
path = Regexp.escape(path).gsub("\\*", "(.*?)")
|
||||
url = Regexp.new("^#{Regexp.escape(scheme)}://#{domain}#{path}")
|
||||
og_video_urls << url
|
||||
end if provider["video_urls"]
|
||||
end
|
||||
|
||||
SECURE_OPENGRAPH_VIDEO_URLS = og_video_urls
|
||||
|
|
|
|||
5
config/open_graph_providers.yml
Normal file
5
config/open_graph_providers.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# SECURITY NOTICE! CROSS-SITE SCRIPTING!
|
||||
# these endpoints may inject html code into our page
|
||||
bandcamp:
|
||||
video_urls:
|
||||
- https://bandcamp.com/EmbeddedPlayer/*/*
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
class AddVideoUrlToOpenGraphCache < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :open_graph_caches, :video_url, :text
|
||||
end
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160822212739) do
|
||||
ActiveRecord::Schema.define(version: 20160901072443) do
|
||||
|
||||
create_table "account_deletions", force: :cascade do |t|
|
||||
t.string "diaspora_handle", limit: 255
|
||||
|
|
@ -300,6 +300,7 @@ ActiveRecord::Schema.define(version: 20160822212739) do
|
|||
t.text "image", limit: 65535
|
||||
t.text "url", limit: 65535
|
||||
t.text "description", limit: 65535
|
||||
t.text "video_url", limit: 65535
|
||||
end
|
||||
|
||||
create_table "participations", force: :cascade do |t|
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ FactoryGirl.define do
|
|||
title "Some article"
|
||||
ob_type "article"
|
||||
description "This is the article lead"
|
||||
video_url "http://example.com/videos/123.html"
|
||||
end
|
||||
|
||||
factory(:tag_following) do
|
||||
|
|
|
|||
|
|
@ -1,30 +1,72 @@
|
|||
describe("app.views.OpenGraph", function() {
|
||||
var open_graph_cache = {
|
||||
context("without a video_url", function() {
|
||||
beforeEach(function() {
|
||||
this.openGraphCache = {
|
||||
"url": "http://example.com/articles/123",
|
||||
"title": "Example title",
|
||||
"description": "Test description",
|
||||
"image": "http://example.com/thumb.jpg",
|
||||
"ob_type": "article"
|
||||
};
|
||||
|
||||
beforeEach(function(){
|
||||
this.statusMessage = factory.statusMessage({
|
||||
"open_graph_cache": open_graph_cache
|
||||
"open_graph_cache": this.openGraphCache
|
||||
});
|
||||
this.view = new app.views.OpenGraph({model: this.statusMessage});
|
||||
});
|
||||
|
||||
this.view = new app.views.OpenGraph({model : this.statusMessage});
|
||||
});
|
||||
|
||||
describe("rendering", function(){
|
||||
it("shows the preview based on the opengraph data", function(){
|
||||
describe("rendering", function() {
|
||||
it("shows the preview based on the opengraph data", function() {
|
||||
this.view.render();
|
||||
var html = this.view.$el.html();
|
||||
|
||||
expect(html).toContain(open_graph_cache.url);
|
||||
expect(html).toContain(open_graph_cache.title);
|
||||
expect(html).toContain(open_graph_cache.description);
|
||||
expect(html).toContain(open_graph_cache.image);
|
||||
expect(html).toContain(this.openGraphCache.url);
|
||||
expect(html).toContain(this.openGraphCache.title);
|
||||
expect(html).toContain(this.openGraphCache.description);
|
||||
expect(html).toContain(this.openGraphCache.image);
|
||||
expect(html).not.toContain("video-overlay");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context("with a video_url", function() {
|
||||
beforeEach(function() {
|
||||
this.openGraphCache = {
|
||||
"url": "http://example.com/articles/123",
|
||||
"title": "Example title",
|
||||
"description": "Test description",
|
||||
"image": "http://example.com/thumb.jpg",
|
||||
"ob_type": "article",
|
||||
"video_url": "http://example.com"
|
||||
};
|
||||
this.statusMessage = factory.statusMessage({
|
||||
"open_graph_cache": this.openGraphCache
|
||||
});
|
||||
this.view = new app.views.OpenGraph({model: this.statusMessage});
|
||||
});
|
||||
|
||||
describe("rendering", function() {
|
||||
it("shows the preview based on the opengraph data", function() {
|
||||
this.view.render();
|
||||
var html = this.view.$el.html();
|
||||
|
||||
expect(html).toContain(this.openGraphCache.url);
|
||||
expect(html).toContain(this.openGraphCache.title);
|
||||
expect(html).toContain(this.openGraphCache.description);
|
||||
expect(html).toContain(this.openGraphCache.image);
|
||||
expect(html).toContain(this.openGraphCache.video_url);
|
||||
expect(html).toContain("video-overlay");
|
||||
});
|
||||
});
|
||||
|
||||
describe("loadVideo", function() {
|
||||
it("adds an iframe with the video", function() {
|
||||
this.view.render();
|
||||
spec.content().html(this.view.$el);
|
||||
expect($("iframe").length).toBe(0);
|
||||
$(".video-overlay").click();
|
||||
expect($("iframe").length).toBe(1);
|
||||
expect($("iframe").attr("src")).toBe(this.openGraphCache.video_url);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
61
spec/models/open_graph_cache_spec.rb
Normal file
61
spec/models/open_graph_cache_spec.rb
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
describe OpenGraphCache, type: :model do
|
||||
describe "fetch_and_save_opengraph_data!" do
|
||||
context "with an unsecure video url" do
|
||||
it "doesn't save the video url" do
|
||||
expect(OpenGraphReader).to receive(:fetch!).with("https://example.com/article/123").and_return(
|
||||
double(
|
||||
og: double(
|
||||
description: "This is the article lead",
|
||||
image: double(url: "https://example.com/image/123.jpg"),
|
||||
title: "Some article",
|
||||
type: "article",
|
||||
url: "https://example.com/acticle/123-seo-foo",
|
||||
video: double(secure_url: "https://example.com/videos/123.html")
|
||||
)
|
||||
)
|
||||
)
|
||||
ogc = OpenGraphCache.new(url: "https://example.com/article/123")
|
||||
ogc.fetch_and_save_opengraph_data!
|
||||
|
||||
expect(ogc.description).to eq("This is the article lead")
|
||||
expect(ogc.image).to eq("https://example.com/image/123.jpg")
|
||||
expect(ogc.title).to eq("Some article")
|
||||
expect(ogc.ob_type).to eq("article")
|
||||
expect(ogc.url).to eq("https://example.com/acticle/123-seo-foo")
|
||||
expect(ogc.video_url).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "with a secure video url" do
|
||||
it "saves the video url" do
|
||||
expect(OpenGraphReader).to receive(:fetch!).with("https://example.com/article/123").and_return(
|
||||
double(
|
||||
og: double(
|
||||
description: "This is the article lead",
|
||||
image: double(url: "https://example.com/image/123.jpg"),
|
||||
title: "Some article",
|
||||
type: "article",
|
||||
url: "https://example.com/acticle/123-seo-foo",
|
||||
video: double(secure_url: "https://bandcamp.com/EmbeddedPlayer/v=2/track=12/size=small")
|
||||
)
|
||||
)
|
||||
)
|
||||
ogc = OpenGraphCache.new(url: "https://example.com/article/123")
|
||||
ogc.fetch_and_save_opengraph_data!
|
||||
|
||||
expect(ogc.description).to eq("This is the article lead")
|
||||
expect(ogc.image).to eq("https://example.com/image/123.jpg")
|
||||
expect(ogc.title).to eq("Some article")
|
||||
expect(ogc.ob_type).to eq("article")
|
||||
expect(ogc.url).to eq("https://example.com/acticle/123-seo-foo")
|
||||
expect(ogc.video_url).to eq("https://bandcamp.com/EmbeddedPlayer/v=2/track=12/size=small")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -133,4 +133,25 @@ describe PostPresenter do
|
|||
expect(PostPresenter.new(reshare).send(:description)).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#build_open_graph_cache" do
|
||||
it "returns a dummy og cache if the og cache is missing" do
|
||||
expect(@presenter.build_open_graph_cache.image).to be_nil
|
||||
end
|
||||
|
||||
context "with an open graph cache" do
|
||||
it "delegates to as_api_response" do
|
||||
og_cache = double("open_graph_cache")
|
||||
expect(og_cache).to receive(:as_api_response).with(:backbone)
|
||||
@presenter.post = double(open_graph_cache: og_cache)
|
||||
@presenter.send(:build_open_graph_cache)
|
||||
end
|
||||
|
||||
it "returns the open graph cache data" do
|
||||
open_graph_cache = FactoryGirl.create(:open_graph_cache)
|
||||
post = FactoryGirl.create(:status_message, public: true, open_graph_cache: open_graph_cache)
|
||||
expect(PostPresenter.new(post).send(:build_open_graph_cache)).to eq(open_graph_cache.as_api_response(:backbone))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue