diff --git a/app/components/shared/embedded_video_component.html.erb b/app/components/shared/embedded_video_component.html.erb new file mode 100644 index 000000000..fbfff8353 --- /dev/null +++ b/app/components/shared/embedded_video_component.html.erb @@ -0,0 +1,5 @@ +
+
+
+
+
diff --git a/app/components/shared/embedded_video_component.rb b/app/components/shared/embedded_video_component.rb new file mode 100644 index 000000000..9f4cdbd6a --- /dev/null +++ b/app/components/shared/embedded_video_component.rb @@ -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] + "" + 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 diff --git a/app/helpers/embed_videos_helper.rb b/app/helpers/embed_videos_helper.rb deleted file mode 100644 index 08a3179f8..000000000 --- a/app/helpers/embed_videos_helper.rb +++ /dev/null @@ -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] - '' - 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 diff --git a/app/models/concerns/videoable.rb b/app/models/concerns/videoable.rb new file mode 100644 index 000000000..1febafcce --- /dev/null +++ b/app/models/concerns/videoable.rb @@ -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 diff --git a/app/models/poll/question/answer/video.rb b/app/models/poll/question/answer/video.rb index 6cf9e7cc6..e353dd365 100644 --- a/app/models/poll/question/answer/video.rb +++ b/app/models/poll/question/answer/video.rb @@ -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 diff --git a/app/models/proposal.rb b/app/models/proposal.rb index f1e4f7198..ca4518b07 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -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 diff --git a/app/views/legislation/proposals/show.html.erb b/app/views/legislation/proposals/show.html.erb index b1485fd99..7ef241fac 100644 --- a/app/views/legislation/proposals/show.html.erb +++ b/app/views/legislation/proposals/show.html.erb @@ -65,13 +65,7 @@
<%= @proposal.summary %>
- <% if @proposal.video_url.present? %> -
-
-
-
-
- <% end %> + <%= render Shared::EmbeddedVideoComponent.new(@proposal) %> <%= auto_link_already_sanitized_html wysiwyg(@proposal.description) %> diff --git a/app/views/proposals/_info.html.erb b/app/views/proposals/_info.html.erb index 23def8f68..3e443b243 100644 --- a/app/views/proposals/_info.html.erb +++ b/app/views/proposals/_info.html.erb @@ -30,13 +30,7 @@
<%= @proposal.summary %>
-<% if @proposal.video_url.present? %> -
-
-
-
-
-<% end %> +<%= render Shared::EmbeddedVideoComponent.new(@proposal) %> <%= auto_link_already_sanitized_html wysiwyg(@proposal.description) %> diff --git a/spec/components/shared/embedded_video_component_spec.rb b/spec/components/shared/embedded_video_component_spec.rb new file mode 100644 index 000000000..e4d9e05f6 --- /dev/null +++ b/spec/components/shared/embedded_video_component_spec.rb @@ -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 diff --git a/spec/system/proposals_spec.rb b/spec/system/proposals_spec.rb index 47db7e6ba..459f7c619 100644 --- a/spec/system/proposals_spec.rb +++ b/spec/system/proposals_spec.rb @@ -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