Merge pull request #5548 from consuldemocracy/video_cookies

Do not use third-party cookies in embedded videos
This commit is contained in:
Javi Martín
2024-06-07 15:42:25 +02:00
committed by GitHub
10 changed files with 151 additions and 74 deletions

View File

@@ -0,0 +1,5 @@
<div class="small-12 medium-7 small-centered">
<div class="flex-video">
<div id="js-embedded-video" data-video-code="<%= embedded_video_code %>"></div>
</div>
</div>

View File

@@ -0,0 +1,59 @@
class Shared::EmbeddedVideoComponent < ApplicationComponent
attr_reader :record
def initialize(record)
@record = record
end
def render?
record.video_url.present?
end
def embedded_video_code
if match && match[2]
"<iframe #{iframe_attributes}></iframe>"
end
end
private
def link
record.video_url
end
def title
t("proposals.show.embed_video_title", proposal: record.title)
end
def server
if link =~ /vimeo.*/
"Vimeo"
elsif link =~ /youtu*.*/
"YouTube"
end
end
def regex
if server == "Vimeo"
record.class::VIMEO_REGEX
elsif server == "YouTube"
record.class::YOUTUBE_REGEX
end
end
def src
if server == "Vimeo"
"https://player.vimeo.com/video/#{match[2]}?dnt=1"
elsif server == "YouTube"
"https://www.youtube-nocookie.com/embed/#{match[2]}"
end
end
def match
@match ||= link.match(regex) if regex
end
def iframe_attributes
tag.attributes(src: src, style: "border:0;", allowfullscreen: true, title: title)
end
end

View File

@@ -1,40 +0,0 @@
module EmbedVideosHelper
VIMEO_REGEX = /vimeo.*(staffpicks\/|channels\/|videos\/|video\/|\/)([^#\&\?]*).*/
YOUTUBE_REGEX = /youtu.*(be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/
def embedded_video_code(resource)
link = resource.video_url
title = t("proposals.show.embed_video_title", proposal: resource.title)
if link =~ /vimeo.*/
server = "Vimeo"
elsif link =~ /youtu*.*/
server = "YouTube"
end
if server == "Vimeo"
reg_exp = VIMEO_REGEX
src = "https://player.vimeo.com/video/"
elsif server == "YouTube"
reg_exp = YOUTUBE_REGEX
src = "https://www.youtube.com/embed/"
end
if reg_exp
match = link.match(reg_exp)
end
if match && match[2]
'<iframe src="' + src + match[2] + '" style="border:0;" allowfullscreen title="' + title + '"></iframe>'
else
""
end
end
def valid_video_url?
return if video_url.blank?
return if video_url.match(VIMEO_REGEX)
return if video_url.match(YOUTUBE_REGEX)
errors.add(:video_url, :invalid)
end
end

View File

@@ -0,0 +1,28 @@
module Videoable
extend ActiveSupport::Concern
included do
validate :valid_video_url?
end
VIMEO_REGEX = /vimeo.*(staffpicks\/|channels\/|videos\/|video\/|\/)([^#\&\?]*).*/
YOUTUBE_REGEX = /youtu.*(be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/
def valid_video_url?
url = send(video_url_field)
return if url.blank?
return if url.match(VIMEO_REGEX)
return if url.match(YOUTUBE_REGEX)
errors.add(video_url_field, :invalid)
end
def video_url_field
if has_attribute?(:video_url)
:video_url
else
:url
end
end
end

View File

@@ -1,17 +1,6 @@
class Poll::Question::Answer::Video < ApplicationRecord
belongs_to :answer, class_name: "Poll::Question::Answer"
VIMEO_REGEX = /vimeo.*(staffpicks\/|channels\/|videos\/|video\/|\/)([^#\&\?]*).*/
YOUTUBE_REGEX = /youtu.*(be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/
include Videoable
validates :title, presence: true
validate :valid_url?
def valid_url?
return if url.blank?
return if url.match(VIMEO_REGEX)
return if url.match(YOUTUBE_REGEX)
errors.add(:url, :invalid)
end
end

View File

@@ -14,7 +14,7 @@ class Proposal < ApplicationRecord
include Mappable
include Notifiable
include Documentable
include EmbedVideosHelper
include Videoable
include Relationable
include Milestoneable
include Randomizable
@@ -59,8 +59,6 @@ class Proposal < ApplicationRecord
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create
validate :valid_video_url?
before_validation :set_responsible_name
before_save :calculate_hot_score, :calculate_confidence_score

View File

@@ -65,13 +65,7 @@
<blockquote><%= @proposal.summary %></blockquote>
<% if @proposal.video_url.present? %>
<div class="small-12 medium-7 small-centered">
<div class="flex-video">
<div id="js-embedded-video" data-video-code="<%= embedded_video_code(@proposal) %>"></div>
</div>
</div>
<% end %>
<%= render Shared::EmbeddedVideoComponent.new(@proposal) %>
<%= auto_link_already_sanitized_html wysiwyg(@proposal.description) %>

View File

@@ -30,13 +30,7 @@
<blockquote><%= @proposal.summary %></blockquote>
<% if @proposal.video_url.present? %>
<div class="small-12 medium-7 small-centered">
<div class="flex-video">
<div id="js-embedded-video" data-video-code="<%= embedded_video_code(@proposal) %>"></div>
</div>
</div>
<% end %>
<%= render Shared::EmbeddedVideoComponent.new(@proposal) %>
<%= auto_link_already_sanitized_html wysiwyg(@proposal.description) %>

View File

@@ -0,0 +1,43 @@
require "rails_helper"
describe Shared::EmbeddedVideoComponent do
describe "src attribute" do
before do
dummy_class = Class.new do
include ActiveModel::Model
attr_accessor :title, :video_url
include Videoable
end
stub_const("DummyClass", dummy_class)
end
let(:record) { DummyClass.new(title: "Dummy Video", video_url: "") }
let(:component) { Shared::EmbeddedVideoComponent.new(record) }
it "does not render anything for empty URls" do
render_inline component
expect(page).not_to be_rendered
end
it "embeds a youtube video for youtube URLs" do
allow(record).to receive(:video_url).and_return "http://www.youtube.com/watch?v=a7UFm6ErMPU"
embed_url = "https://www.youtube-nocookie.com/embed/a7UFm6ErMPU"
render_inline component
expect(page).to have_css "[data-video-code*='src=\"#{embed_url}\"']"
end
it "embeds a vimeo video for vimeo URLs" do
allow(record).to receive(:video_url).and_return "https://vimeo.com/7232823"
embed_url = "https://player.vimeo.com/video/7232823?dnt=1"
render_inline component
expect(page).to have_css "[data-video-code*='src=\"#{embed_url}\"']"
end
end
end

View File

@@ -301,23 +301,30 @@ describe "Proposals" do
context "Embedded video" do
scenario "Show YouTube video" do
proposal = create(:proposal, video_url: "http://www.youtube.com/watch?v=a7UFm6ErMPU")
visit proposal_path(proposal)
expect(page).to have_css "div[id='js-embedded-video']"
expect(page.html).to include "https://www.youtube.com/embed/a7UFm6ErMPU"
within "#js-embedded-video" do
expect(page).to have_css "iframe[src='https://www.youtube-nocookie.com/embed/a7UFm6ErMPU']"
end
end
scenario "Show Vimeo video" do
proposal = create(:proposal, video_url: "https://vimeo.com/7232823")
visit proposal_path(proposal)
expect(page).to have_css "div[id='js-embedded-video']"
expect(page.html).to include "https://player.vimeo.com/video/7232823"
within "#js-embedded-video" do
expect(page).to have_css "iframe[src='https://player.vimeo.com/video/7232823?dnt=1']"
end
end
scenario "Dont show video" do
proposal = create(:proposal, video_url: nil)
visit proposal_path(proposal)
expect(page).not_to have_css "div[id='js-embedded-video']"
expect(page).not_to have_css "#js-embedded-video"
end
end