diff --git a/app/assets/javascripts/channels/broadcasts.coffee b/app/assets/javascripts/channels/broadcasts.coffee index 7b5367f..467671c 100644 --- a/app/assets/javascripts/channels/broadcasts.coffee +++ b/app/assets/javascripts/channels/broadcasts.coffee @@ -1,13 +1,8 @@ $(document).on "turbolinks:load", -> - # Only connect if a broadcast-token meta tag is present - broadcast_meta = document.querySelector("meta[name=broadcast-token]") - return unless broadcast_meta - - broadcastToken = broadcast_meta.getAttribute("content") - - App.public = App.cable.subscriptions.create { channel: "BroadcastsChannel", token: broadcastToken }, + subscribeToBroadcast = (broadcastToken) -> App.cable.subscriptions.create { channel: "BroadcastsChannel", token: broadcastToken }, connected: -> # Called when the subscription is ready for use on the server + console.info "Subscribed to channel for broadcast:#{broadcastToken}" disconnected: -> # Called when the subscription has been terminated by the server @@ -17,7 +12,7 @@ $(document).on "turbolinks:load", -> switch data.event when "broadcast_stream_update" then @refreshBroadcastVideo(data) when "stream_recording_ready" then @showBroadcastRecordings(data) - when "file_upload_update" then @refreshFilesTab(data) + when "file_upload_update" then @refreshBroadcastFilesTab(data) refreshBroadcastVideo: (data) -> $("#broadcast_updates").html data.status_content @@ -38,8 +33,12 @@ $(document).on "turbolinks:load", -> $(".flash-message").html data.flash_content $("#broadcast_recordings").html data.recordings_content $("#broadcast_recordings_nav").html data.recordings_nav_content - - refreshFilesTab: (data) -> - $("#broadcast_file_list").html data.files_content - $("#broadcast_files_pagination").html data.pagination_content - \ No newline at end of file + + refreshBroadcastFilesTab: (data) -> + $("#broadcast_file_list_#{data.broadcast_token}").html data.files_content + $("#broadcast_files_pagination_#{data.broadcast_token}").html data.pagination_content + + # Create a channel subscription for every broadcast included in the meta tags + get_token = (meta) -> meta.getAttribute("content") + broadcast_tokens = (get_token broadcast_meta for broadcast_meta in document.querySelectorAll("meta[name=broadcast-token]")) + subscribeToBroadcast token for token in broadcast_tokens diff --git a/app/assets/javascripts/multi_view_broadcasts.js b/app/assets/javascripts/multi_view_broadcasts.js index 27325ab..f313ab8 100644 --- a/app/assets/javascripts/multi_view_broadcasts.js +++ b/app/assets/javascripts/multi_view_broadcasts.js @@ -39,7 +39,7 @@ function selectBroadcast(clicked_element, checkbox) { if (broadcast_ids.length >= 2) { multi_view_ids = $.param({multi_view_ids: broadcast_ids}); broadcast_url = "/en/projects/" + project_id + "/broadcasts/" + broadcast_ids[0] + "?" + multi_view_ids - + $("#multi_view_broadcasts").attr("href", broadcast_url); $("#multi_view_broadcasts").attr("target", "_blank"); $("#multi_view_broadcasts").removeClass('disabled'); diff --git a/app/channels/broadcasts_channel.rb b/app/channels/broadcasts_channel.rb index e3014e6..dd3d941 100644 --- a/app/channels/broadcasts_channel.rb +++ b/app/channels/broadcasts_channel.rb @@ -35,11 +35,12 @@ class BroadcastsChannel < ApplicationCable::Channel recordings_nav_content: recordings_nav_content end - def self.file_upload_updates(broadcast, files, pagination_content) + def self.broadcast_file_upload_updates(broadcast, files, pagination_content) files_content = ApplicationController.render partial: "broadcasts/file", collection: files broadcast_to broadcast, { event: :file_upload_update, + broadcast_token: broadcast.token, files_content: files_content, pagination_content: pagination_content } diff --git a/app/controllers/broadcasts_controller.rb b/app/controllers/broadcasts_controller.rb index 2d69383..c83338a 100644 --- a/app/controllers/broadcasts_controller.rb +++ b/app/controllers/broadcasts_controller.rb @@ -1,6 +1,6 @@ class BroadcastsController < ApplicationController layout "project" - + before_action :set_project before_action :build_broadcast, only: [:new, :create] before_action :set_broadcast, only: [:show, :destroy, :update] @@ -24,19 +24,19 @@ class BroadcastsController < ApplicationController end end + def show + @conference_url = url_for [@broadcast.project, @broadcast, :zoom_meeting] + @recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page]) + @files = @broadcast.files.order("created_at DESC").paginate(page: params[:files_page]) + render layout: 'application' + end + def update @broadcast.update(broadcast_params) @files = @broadcast.files.order("created_at DESC").paginate(page: 1) - pagination_content = ApplicationController.render html: helpers.will_paginate(@files, params: { active_tab: params[:active_tab] }) - BroadcastsChannel.file_upload_updates(@broadcast, @files, pagination_content) - end - - def show - @conference_url = url_for [@broadcast.project, @broadcast, :zoom_meeting] - @recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page]) - @files = @broadcast.files.order("created_at DESC").paginate(page: params[:page]) - render layout: 'application' + pagination_content = ApplicationController.render html: helpers.will_paginate(@files, params: { active_tab: params[:active_tab], page: params[:page], active_files_tab: params[:active_files_tab] }) + BroadcastsChannel.broadcast_file_upload_updates(@broadcast, @files, pagination_content) end def destroy @@ -71,7 +71,10 @@ class BroadcastsController < ApplicationController def set_multi_view_broadcasts authorized_broadcasts = authorize policy_scope(Broadcast).where(id: params[:multi_view_ids]).order_by_recent - @multi_view_broadcasts = authorized_broadcasts.map { |b| MultiViewBroadcast.new(b, params[:multi_view_ids]) } + @multi_view_broadcasts = authorized_broadcasts.map do |b| + files_page = params[:files_page] if params[:active_files_tab] == b.token + MultiViewBroadcast.new(b, params[:multi_view_ids], files_page) + end end def filtered_broadcasts @@ -90,20 +93,29 @@ class BroadcastsController < ApplicationController class MultiViewBroadcast include Rails.application.routes.url_helpers - + delegate_missing_to :@broadcast - - def initialize(broadcast, multi_view_ids) + + def initialize(broadcast, multi_view_ids, paginate_page) @broadcast = broadcast @multi_view_ids = multi_view_ids + @paginate_page = paginate_page end def url project_broadcast_path(@broadcast.project, @broadcast, multi_view_ids: @multi_view_ids, locale: I18n.locale) end - + + def files + @broadcast.files.order("created_at DESC").paginate(page: @paginate_page) + end + def uid id end + + def self.model_name + Broadcast.model_name + end end end diff --git a/app/controllers/public/broadcasts_controller.rb b/app/controllers/public/broadcasts_controller.rb index b71c338..1f7d35b 100644 --- a/app/controllers/public/broadcasts_controller.rb +++ b/app/controllers/public/broadcasts_controller.rb @@ -6,8 +6,8 @@ class Public::BroadcastsController < Public::BaseController @conference_url = broadcast_zoom_meeting_url(@broadcast.token) @multi_view_broadcasts = multi_view_broadcasts @recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page]) - @files = @broadcast.files.order("created_at DESC").paginate(page: params[:page]) - + @files = @broadcast.files.order("created_at DESC").paginate(page: params[:files_page]) + render 'broadcasts/show' end @@ -15,8 +15,8 @@ class Public::BroadcastsController < Public::BaseController @broadcast.update(broadcast_params) @files = @broadcast.files.order("created_at DESC").paginate(page: 1) - pagination_content = ApplicationController.render html: helpers.will_paginate(@files, params: { active_tab: params[:active_tab] }) - BroadcastsChannel.file_upload_updates(@broadcast, @files, pagination_content) + pagination_content = ApplicationController.render html: helpers.will_paginate(@files,params: { active_tab: params[:active_tab], page: params[:page], active_files_tab: params[:active_files_tab] }) + BroadcastsChannel.broadcast_file_upload_updates(@broadcast, @files, pagination_content) end private @@ -29,7 +29,10 @@ class Public::BroadcastsController < Public::BaseController Broadcast. where(token: params[:multi_view_tokens]). order_by_recent. - map { |b| MultiViewBroadcast.new(b, params[:multi_view_tokens]) } + map do |b| + files_page = params[:files_page] if params[:active_files_tab] == b.token + MultiViewBroadcast.new(b, params[:multi_view_tokens], files_page) + end end def set_broadcast @@ -38,20 +41,29 @@ class Public::BroadcastsController < Public::BaseController class MultiViewBroadcast include Rails.application.routes.url_helpers - + delegate_missing_to :@broadcast - - def initialize(broadcast, multi_view_tokens) + + def initialize(broadcast, multi_view_tokens, paginate_page) @broadcast = broadcast @multi_view_tokens = multi_view_tokens + @paginate_page = paginate_page end def url broadcast_url(uid, multi_view_tokens: @multi_view_tokens, host: AppHost.new.domain_with_port, locale: I18n.locale) end - + + def files + @broadcast.files.order("created_at DESC").paginate(page: @paginate_page) + end + def uid token end + + def self.model_name + Broadcast.model_name + end end end diff --git a/app/views/broadcasts/_file_form.html.erb b/app/views/broadcasts/_file_form.html.erb index 21a333d..55714a5 100644 --- a/app/views/broadcasts/_file_form.html.erb +++ b/app/views/broadcasts/_file_form.html.erb @@ -1,4 +1,4 @@ <%= bootstrap_form_for model, layout: :inline, remote: true do |form| %> - <%= form.file_field :files, direct_upload: true, multiple: true, accept: "*", hide_label: true, wrapper_class: "w-65 mr-2" %> + <%= form.file_field :files, direct_upload: true, multiple: true, accept: "*", hide_label: true, wrapper_class: "w-65 mr-2", id: "broadcast_files_#{token}" %> <%= form.button fa_icon("upload", text: "Add File"), class: "btn btn-primary", type: :submit, data: { disable_with: fa_icon("spinner", text: "Adding File") } %> <% end %> diff --git a/app/views/broadcasts/_files_section.html.erb b/app/views/broadcasts/_files_section.html.erb new file mode 100644 index 0000000..86865c8 --- /dev/null +++ b/app/views/broadcasts/_files_section.html.erb @@ -0,0 +1,21 @@ +
+ <% if controller.class.module_parent.to_s == "Public" %> + <%= render partial: "public/broadcasts/file_form", locals: { model: [broadcast], token: broadcast.token } %> + <% else %> + <%= render partial: "broadcasts/file_form", locals: { model: [broadcast.project, broadcast], token: broadcast.token } %> + <% end %> +
+
+ +
+ <%= will_paginate(files, param_name: 'files_page', params: { active_files_tab: broadcast.token }) if files.present? %> +
+
diff --git a/app/views/broadcasts/show.html.erb b/app/views/broadcasts/show.html.erb index 561ce71..95ff3fb 100644 --- a/app/views/broadcasts/show.html.erb +++ b/app/views/broadcasts/show.html.erb @@ -5,6 +5,12 @@ <% if @broadcast %> <% end %> + <% # Subscribe to Action Cable for every broadcast including those in multi-view %> + <% @multi_view_broadcasts.each do |multi_view_broadcast| %> + <% if multi_view_broadcast.token != @broadcast.token %> + + <% end %> + <% end %> <% end %> <% content_for :header do %> @@ -24,9 +30,7 @@

<%= @broadcast.name %>

+ + +
+
+

Files

+ <% if @multi_view_broadcasts %> + + <% end %> +
+
+
+ <% if @multi_view_broadcasts.present? %> + <% @multi_view_broadcasts.each_with_index do |mvb, index| %> +
(params[:active_files_tab] == mvb.token || (params[:active_files_tab].nil? && index == 0))) %>" id="files_broadcast_<%= mvb.token %>"> + <%= render partial: 'broadcasts/files_section', locals: { broadcast: mvb, files: mvb.files } %> +
+ <% end %> + <% else %> +
+ <%= render partial: 'broadcasts/files_section', locals: { broadcast: @broadcast, files: @files } %> +
+ <% end %> +
+
+
diff --git a/app/views/broadcasts/update.js.erb b/app/views/broadcasts/update.js.erb index 92d4bbb..a46716a 100644 --- a/app/views/broadcasts/update.js.erb +++ b/app/views/broadcasts/update.js.erb @@ -1,9 +1,9 @@ -$("#broadcast_file_form").html("<%= j render(partial: "broadcasts/file_form", locals: { model: [@project, @broadcast] }) %>"); +$("#broadcast_file_form_<%= @broadcast.token %>").html("<%= j render(partial: "broadcasts/file_form", locals: { model: [@project, @broadcast], token: @broadcast.token }) %>"); var file_id = "#<%= dom_id(@files.first) %>" -if ($("#broadcast_file_list").has(file_id).length == 0) { - $("#broadcast_file_list").html("<%= j render(partial: "broadcasts/file", collection: @files) %>"); - $("#broadcast_files_pagination").html("<%= j will_paginate(@files) %>"); +if ($("#broadcast_file_list_<%= @broadcast.token %>").has(file_id).length == 0) { + $("#broadcast_file_list_<%= @broadcast.token %>").html("<%= j render(partial: "broadcasts/file", collection: @files) %>"); + $("#broadcast_files_pagination_<%= @broadcast.token %>").html("<%= j will_paginate(@files, param_name: 'files_page', params: { active_files_tab: @broadcast.token }) %>"); } -bsCustomFileInput.init(); \ No newline at end of file +bsCustomFileInput.init(); diff --git a/app/views/public/broadcasts/_file_form.html.erb b/app/views/public/broadcasts/_file_form.html.erb index 3935c63..5830c05 100644 --- a/app/views/public/broadcasts/_file_form.html.erb +++ b/app/views/public/broadcasts/_file_form.html.erb @@ -1,4 +1,4 @@ <%= bootstrap_form_for model, url: broadcast_url(token: token), layout: :inline, remote: true do |form| %> - <%= form.file_field :files, direct_upload: true, multiple: true, accept: "*", hide_label: true, wrapper_class: "w-65 mr-2" %> + <%= form.file_field :files, direct_upload: true, multiple: true, accept: "*", hide_label: true, wrapper_class: "w-65 mr-2", id: "broadcast_files_#{token}" %> <%= form.button fa_icon("upload", text: "Add File"), class: "btn btn-primary", type: :submit, data: { disable_with: fa_icon("spinner", text: "Adding File") } %> <% end %> \ No newline at end of file diff --git a/app/views/public/broadcasts/update.js.erb b/app/views/public/broadcasts/update.js.erb index 5497ff5..4e4a2e8 100644 --- a/app/views/public/broadcasts/update.js.erb +++ b/app/views/public/broadcasts/update.js.erb @@ -1,9 +1,9 @@ -$("#broadcast_file_form").html("<%= j render(partial: "public/broadcasts/file_form", locals: { model: [@project, @broadcast], token: @broadcast.token }) %>"); +$("#broadcast_file_form_<%= @broadcast.token %>").html("<%= j render(partial: "public/broadcasts/file_form", locals: { model: [@project, @broadcast], token: @broadcast.token }) %>"); var file_id = "#<%= dom_id(@files.first) %>" -if ($("#broadcast_file_list").has(file_id).length == 0) { - $("#broadcast_file_list").html("<%= j render(partial: "broadcasts/file", collection: @files) %>"); - $("#broadcast_files_pagination").html("<%= j will_paginate(@files) %>"); +if ($("#broadcast_file_list_<%= @broadcast.token %>").has(file_id).length == 0) { + $("#broadcast_file_list_<%= @broadcast.token %>").html("<%= j render(partial: "broadcasts/file", collection: @files) %>"); + $("#broadcast_files_pagination_<%= @broadcast.token %>").html("<%= j will_paginate(@files) %>"); } bsCustomFileInput.init(); \ No newline at end of file diff --git a/spec/channels/broadcasts_channel_spec.rb b/spec/channels/broadcasts_channel_spec.rb index 9622ed2..2149998 100644 --- a/spec/channels/broadcasts_channel_spec.rb +++ b/spec/channels/broadcasts_channel_spec.rb @@ -50,4 +50,21 @@ RSpec.describe BroadcastsChannel, type: :channel do }) end end + + + describe ".broadcast_file_upload_updates" do + it 'broadcasts to the channel with the right data' do + broadcast = create(:broadcast, :with_stream, :with_files, skip_create_callback: true) + files_content = ApplicationController.render partial: "broadcasts/file", collection: broadcast.files + + expect { + BroadcastsChannel.broadcast_file_upload_updates(broadcast, broadcast.files, "pagination_content") + }.to have_broadcasted_to(broadcast).with({ + event: 'file_upload_update', + broadcast_token: broadcast.token, + files_content: files_content, + pagination_content: "pagination_content" + }) + end + end end diff --git a/spec/controllers/broadcasts_controller_spec.rb b/spec/controllers/broadcasts_controller_spec.rb index c1c65f6..08b686a 100644 --- a/spec/controllers/broadcasts_controller_spec.rb +++ b/spec/controllers/broadcasts_controller_spec.rb @@ -111,17 +111,6 @@ RSpec.describe BroadcastsController, type: :controller do end end - describe "#update" do - let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, project: project ) } - - it "uploads files to broadcast" do - patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true - - expect(broadcast.files.count).to eq(1) - expect(broadcast.files.first.filename).to eq("contract.pdf") - end - end - describe "#show" do let(:broadcast) { create(:broadcast, project: project, name: "Another Broadcast") } @@ -198,6 +187,25 @@ RSpec.describe BroadcastsController, type: :controller do end end + describe "#update" do + let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, project: project ) } + + it "uploads files to broadcast" do + patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true + + expect(broadcast.files.count).to eq(1) + expect(broadcast.files.first.filename).to eq("contract.pdf") + end + + it "sends an update to the broadcasts channel" do + allow(BroadcastsChannel).to receive(:broadcast_file_upload_updates) + + patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true + + expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates) + end + end + describe "#destroy" do let!(:broadcast_2) { create(:broadcast, :with_stream, skip_create_callback: true, project: project, name: "Another Broadcast") } diff --git a/spec/controllers/public/broadcasts_controller_spec.rb b/spec/controllers/public/broadcasts_controller_spec.rb index ad10b87..8850bd7 100644 --- a/spec/controllers/public/broadcasts_controller_spec.rb +++ b/spec/controllers/public/broadcasts_controller_spec.rb @@ -92,6 +92,14 @@ RSpec.describe Public::BroadcastsController, type: :controller do expect(broadcast.files.count).to eq(1) expect(broadcast.files.first.filename).to eq("contract.pdf") end + + it "sends an update to the broadcasts channel" do + allow(BroadcastsChannel).to receive(:broadcast_file_upload_updates) + + patch :update, params: { token: broadcast.token, broadcast: file_params }, xhr: true + + expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates) + end end after do diff --git a/spec/features/user_managing_broadcasts_spec.rb b/spec/features/user_managing_broadcasts_spec.rb index 5414351..27e8741 100644 --- a/spec/features/user_managing_broadcasts_spec.rb +++ b/spec/features/user_managing_broadcasts_spec.rb @@ -46,15 +46,17 @@ feature "User managing broadcasts" do expect(page).to have_content("Live stream is waiting to begin.") expect(page).to have_content("Copy URL") - click_on "Files" - expect(page).to have_content("contract.pdf") + within "#files" do + expect(page).to have_content("contract.pdf") + end click_on "Previous Sessions" expect(page).to have_content(recording.download_file_name) end scenario "visit multi-view broadcast page", js: true do - broadcasts = create_list(:broadcast, 4, :with_stream, project: project) + broadcast_one = create(:broadcast, :with_stream, :with_files, name: "Broadcast 1", project: project) + broadcast_two = create(:broadcast, :with_stream, :with_files, name: "Broadcast 2", project: project) visit project_broadcasts_path(project) click_checkboxes @@ -64,8 +66,16 @@ feature "User managing broadcasts" do expect(page).to have_content("Switch View") click_on "Switch View" - expect(page).to have_link(broadcasts.first.name) - expect(page).to have_link(broadcasts.second.name) + expect(page).to have_link("Broadcast 1") + expect(page).to have_link("Broadcast 2") + + within "#files" do + click_on "Broadcast 1" + expect(page).to have_content("contract.pdf") + + click_on "Broadcast 2" + expect(page).to have_content("contract.pdf") + end end end end @@ -77,7 +87,7 @@ feature "User managing broadcasts" do end def click_checkboxes + all('input[type="checkbox"]')[0].click all('input[type="checkbox"]')[1].click - all('input[type="checkbox"]')[2].click end end