Compare commits
5 Commits
allow-seek
...
allow-mana
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9edfe3d291 | ||
|
|
7ef27d4c1d | ||
|
|
f8bdc5bce5 | ||
|
|
86e441eebd | ||
|
|
8f13589c55 |
@@ -26,7 +26,7 @@ $(document).on "turbolinks:load", ->
|
||||
$("#broadcast_video").html data.video_content
|
||||
new (Clappr.Player)(
|
||||
parentId: '#broadcast_video'
|
||||
source: data.playback_url
|
||||
source: data.full_live_stream_playback_url
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
mute: true,
|
||||
|
||||
@@ -16,6 +16,7 @@ class BroadcastsChannel < ApplicationCable::Channel
|
||||
event: :broadcast_stream_update,
|
||||
status: broadcast.status,
|
||||
playback_url: broadcast.stream_playback_url,
|
||||
full_live_stream_playback_url: broadcast.full_live_stream_playback_url,
|
||||
video_content: video_content,
|
||||
status_content: status_content,
|
||||
streamer_status: broadcast.streamer_status
|
||||
|
||||
@@ -3,7 +3,7 @@ class BroadcastsController < ApplicationController
|
||||
|
||||
before_action :set_project
|
||||
before_action :build_broadcast, only: [:new, :create]
|
||||
before_action :set_broadcast, only: [:show, :destroy, :update]
|
||||
before_action :set_broadcast, only: [:show, :destroy, :update, :destroy_file]
|
||||
before_action :set_multi_view_broadcasts, only: [:show]
|
||||
before_action :show_splash_screen, only: :index
|
||||
|
||||
@@ -39,10 +39,7 @@ class BroadcastsController < ApplicationController
|
||||
end
|
||||
|
||||
@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], page: params[:page], active_files_tab: params[:active_files_tab] })
|
||||
BroadcastsChannel.broadcast_file_upload_updates(@broadcast, @files, pagination_content)
|
||||
update_files_section
|
||||
end
|
||||
|
||||
def destroy
|
||||
@@ -53,8 +50,23 @@ class BroadcastsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_file
|
||||
authorize Broadcast
|
||||
file = ActiveStorage::Attachment.find(params[:file_id])
|
||||
file.destroy
|
||||
|
||||
update_files_section
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_files_section
|
||||
@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], page: params[:page], active_files_tab: params[:active_files_tab] })
|
||||
BroadcastsChannel.broadcast_file_upload_updates(@broadcast, @files, pagination_content)
|
||||
end
|
||||
|
||||
def show_splash_screen
|
||||
render :splash if broadcasts.count.zero?
|
||||
end
|
||||
|
||||
@@ -14,6 +14,10 @@ class StreamNotificationsController < ApplicationController
|
||||
when "video.live_stream.recording"
|
||||
@broadcast.streamer_recording!
|
||||
notify_users
|
||||
when "video.asset.ready"
|
||||
full_live_stream_playback_uid = notification.dig(:data, :playback_ids, 0, :id)
|
||||
@broadcast.update(full_live_stream_playback_uid: full_live_stream_playback_uid)
|
||||
notify_users
|
||||
when "video.live_stream.active"
|
||||
@broadcast.active!
|
||||
notify_users
|
||||
@@ -59,7 +63,8 @@ class StreamNotificationsController < ApplicationController
|
||||
end
|
||||
|
||||
def set_broadcast
|
||||
if notification_type == "video.asset.static_renditions.ready"
|
||||
case notification_type
|
||||
when "video.asset.static_renditions.ready", "video.asset.ready"
|
||||
live_stream_id = notification.dig(:stream_notification, :data, :live_stream_id)
|
||||
@broadcast = Broadcast.find_by(stream_uid: live_stream_id)
|
||||
else
|
||||
|
||||
@@ -30,6 +30,10 @@ class Broadcast < ApplicationRecord
|
||||
"https://stream.mux.com/#{stream_playback_uid}.m3u8"
|
||||
end
|
||||
|
||||
def full_live_stream_playback_url
|
||||
full_live_stream_playback_uid.blank? ? stream_playback_url : "https://stream.mux.com/#{full_live_stream_playback_uid}.m3u8"
|
||||
end
|
||||
|
||||
def stream_server_url
|
||||
ENV['MUX_BROADCAST_SERVER_URL']
|
||||
end
|
||||
|
||||
@@ -18,4 +18,12 @@ class BroadcastPolicy < ApplicationPolicy
|
||||
def update?
|
||||
true
|
||||
end
|
||||
|
||||
def destroy_file?
|
||||
if user.nil? || user.user.nil?
|
||||
return false
|
||||
end
|
||||
|
||||
user.manager? || user.account_manager?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
<li class="my-2" id="<%= dom_id(file) %>">
|
||||
<% if file.variable? %>
|
||||
<%= link_to image_tag(file.variant(resize_and_pad: [300, 300, background: "#F7F8F9"]), class: "bg-light img-thumbnail img-fluid"), file, target: "_blank" %>
|
||||
<% else %>
|
||||
<div class="border rounded bg-light text-muted d-flex justify-content-center align-items-center fix-h-and-w">
|
||||
<%= link_to file, target: "_blank" do %>
|
||||
<%= fa_icon("file", style: "font-size: 2rem") %>
|
||||
<div class="mt-2"><%= file.filename %></div>
|
||||
<div class="row">
|
||||
<% broadcast = file.record %>
|
||||
<% show_delete = controller.class.module_parent.to_s == "Public" ? false : policy(broadcast).destroy_file? %>
|
||||
<% file_class = show_delete ? "col-8" : "col-12" %>
|
||||
<div class="<%= file_class %>">
|
||||
<li class="my-2" id="<%= dom_id(file) %>">
|
||||
<% if file.variable? %>
|
||||
<%= link_to image_tag(file.variant(resize_and_pad: [300, 300, background: "#F7F8F9"]), class: "bg-light img-thumbnail img-fluid"), file, target: "_blank" %>
|
||||
<% else %>
|
||||
<div class="border rounded bg-light text-muted d-flex justify-content-center align-items-center img-fluid fix-h-and-w">
|
||||
<%= link_to file, target: "_blank" do %>
|
||||
<%= fa_icon("file", style: "font-size: 2rem") %>
|
||||
<div class="mt-2"><%= file.filename %></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
</div>
|
||||
<% if show_delete %>
|
||||
<div class="col-4 align-self-center p-0 m-0">
|
||||
<% url = url_for [:destroy_file, broadcast.project, broadcast, { file_id: file.id }] %>
|
||||
<%= link_to fa_icon("trash fw", text: t('.actions.delete_file')), url, class: "btn btn-danger", remote: true, method: :delete, data: { confirm: t('.confirm_delete') } %>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
</div>
|
||||
@@ -214,6 +214,10 @@ en:
|
||||
destroy:
|
||||
alert: A live stream has been deleted
|
||||
api_error: Something went wrong, please try again later after some time
|
||||
file:
|
||||
actions:
|
||||
delete_file: Delete
|
||||
confirm_delete: Are you sure?
|
||||
index:
|
||||
actions:
|
||||
new: Create New Live Stream
|
||||
|
||||
@@ -81,6 +81,10 @@ es:
|
||||
do_not_copy_warning: "Do not copy (ES)"
|
||||
serial_number_label: "Serial Number (ES)"
|
||||
broadcasts:
|
||||
file:
|
||||
actions:
|
||||
delete_file: Delete
|
||||
confirm_delete: Are you sure? (ES)
|
||||
show:
|
||||
actions:
|
||||
reset_url: Reset URL (ES)
|
||||
|
||||
@@ -96,6 +96,9 @@ Rails.application.routes.draw do
|
||||
end
|
||||
resources :projects, only: [] do
|
||||
resources :broadcasts, except: [:edit] do
|
||||
member do
|
||||
delete :destroy_file
|
||||
end
|
||||
resource :zoom_meeting, only: [:show]
|
||||
end
|
||||
resources :directories, except: [:index] do
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddFullLiveStreamPlaybackUrlToBroadcasts < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :broadcasts, :full_live_stream_playback_uid, :string
|
||||
end
|
||||
end
|
||||
@@ -9,20 +9,6 @@ SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
--
|
||||
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
|
||||
--
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
|
||||
|
||||
|
||||
--
|
||||
-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
|
||||
|
||||
|
||||
--
|
||||
-- Name: fuzzystrmatch; Type: EXTENSION; Schema: -; Owner: -
|
||||
--
|
||||
@@ -554,7 +540,8 @@ CREATE TABLE public.broadcasts (
|
||||
stream_playback_uid character varying,
|
||||
token character varying,
|
||||
streamer_status integer DEFAULT 0,
|
||||
shoot_location_time_zone character varying DEFAULT 'UTC'::character varying
|
||||
shoot_location_time_zone character varying DEFAULT 'UTC'::character varying,
|
||||
full_live_stream_playback_uid character varying
|
||||
);
|
||||
|
||||
|
||||
@@ -3954,6 +3941,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||
('20200716094927'),
|
||||
('20200716103525'),
|
||||
('20200716105723'),
|
||||
('20200720051634');
|
||||
('20200720051634'),
|
||||
('20200720131309');
|
||||
|
||||
|
||||
|
||||
11246
package-lock.json
generated
11246
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@ RSpec.describe BroadcastsChannel, type: :channel do
|
||||
event: "broadcast_stream_update",
|
||||
status: broadcast.status,
|
||||
playback_url: broadcast.stream_playback_url,
|
||||
full_live_stream_playback_url: broadcast.full_live_stream_playback_url,
|
||||
status_content: status_content,
|
||||
video_content: video_content,
|
||||
streamer_status: broadcast.streamer_status
|
||||
|
||||
@@ -106,7 +106,7 @@ RSpec.describe Api::BroadcastsController, type: :controller do
|
||||
included = JSON.parse(response.body).dig('included')
|
||||
|
||||
expect(relationships.keys).to include('files')
|
||||
expect(included.size).to eq 1
|
||||
expect(included.size).to eq 3
|
||||
expect(included.first.dig("id")).to eq broadcast.files.first.id.to_s
|
||||
expect(included.first.dig("type")).to eq 'active_storage_attachment'
|
||||
end
|
||||
|
||||
@@ -87,6 +87,7 @@ RSpec.describe Public::BroadcastsController, type: :controller do
|
||||
let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, project: project ) }
|
||||
|
||||
it "uploads files to broadcast" do
|
||||
allow(BroadcastsChannel).to receive(:broadcast_file_upload_updates)
|
||||
patch :update, params: { token: broadcast.token, broadcast: file_params }, xhr: true
|
||||
|
||||
expect(broadcast.files.count).to eq(1)
|
||||
|
||||
@@ -4,27 +4,45 @@ RSpec.describe StreamNotificationsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, name: "Live Stream") }
|
||||
let(:active_status) { {type: "video.live_stream.active", object: { id: "mux_stream" }} }
|
||||
let(:disconnected_status) { {type: "video.live_stream.disconnected", object: { id: "mux_stream" }} }
|
||||
let(:idle_status) { {type: "video.live_stream.idle", object: { id: "mux_stream" }} }
|
||||
let(:idle_status_for_unknown_broadcast) { {type: "video.live_stream.idle", object: { id: "unknown-id" }} }
|
||||
let(:asset_ready) { {
|
||||
type: "video.asset.static_renditions.ready",
|
||||
object: { id: "asset_uid" },
|
||||
data: {
|
||||
playback_ids: [
|
||||
{id: "playback_uid"}
|
||||
],
|
||||
static_renditions: {
|
||||
files: [{name: "high.mp4"}]
|
||||
}
|
||||
},
|
||||
stream_notification: {
|
||||
let(:active_status) { { type: "video.live_stream.active", object: { id: "mux_stream" } } }
|
||||
let(:disconnected_status) { { type: "video.live_stream.disconnected", object: { id: "mux_stream" } } }
|
||||
let(:idle_status) { { type: "video.live_stream.idle", object: { id: "mux_stream" } } }
|
||||
let(:idle_status_for_unknown_broadcast) { { type: "video.live_stream.idle", object: { id: "unknown-id" } } }
|
||||
let(:asset_ready) do
|
||||
{
|
||||
type: "video.asset.static_renditions.ready",
|
||||
object: { id: "asset_uid" },
|
||||
data: {
|
||||
live_stream_id: "mux_stream"
|
||||
playback_ids: [
|
||||
{ id: "playback_uid" }
|
||||
],
|
||||
static_renditions: {
|
||||
files: [{ name: "high.mp4" }]
|
||||
}
|
||||
},
|
||||
stream_notification: {
|
||||
data: {
|
||||
live_stream_id: "mux_stream"
|
||||
}
|
||||
}
|
||||
}
|
||||
} }
|
||||
end
|
||||
let(:full_live_stream_ready) do
|
||||
{
|
||||
type: "video.asset.ready",
|
||||
object: { id: "active_asset_uid" },
|
||||
data: {
|
||||
playback_ids: [
|
||||
{ id: "full_live_stream_playback_uid" }
|
||||
]
|
||||
},
|
||||
stream_notification: {
|
||||
data: {
|
||||
live_stream_id: "mux_stream"
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
describe "#create" do
|
||||
before do
|
||||
@@ -54,13 +72,20 @@ RSpec.describe StreamNotificationsController, type: :controller do
|
||||
end
|
||||
|
||||
it "creates a broadcast recording when static_renditions.ready is received in notification" do
|
||||
expect {
|
||||
expect do
|
||||
post :create, params: asset_ready
|
||||
}.to change(BroadcastRecording, :count).by(1)
|
||||
end.to change(BroadcastRecording, :count).by(1)
|
||||
|
||||
expect(BroadcastsChannel).to have_received(:stream_recording_ready)
|
||||
end
|
||||
|
||||
it "stores full livestream playback uid and updates the broadcast" do
|
||||
post :create, params: full_live_stream_ready
|
||||
|
||||
expect(Broadcast.last.full_live_stream_playback_uid).to eq "full_live_stream_playback_uid"
|
||||
expect(BroadcastsChannel).to have_received(:broadcast_stream_updates).with(be_kind_of(Broadcast))
|
||||
end
|
||||
|
||||
it "returns OK response even for non-existing broadcast" do
|
||||
post :create, params: idle_status_for_unknown_broadcast
|
||||
|
||||
|
||||
@@ -11,12 +11,19 @@ FactoryBot.define do
|
||||
stream_uid "mux_stream"
|
||||
stream_key "mux_key"
|
||||
stream_playback_uid "mux_playback_id"
|
||||
full_live_stream_playback_uid "full_live_stream_playback_uid"
|
||||
status "created"
|
||||
streamer_status "idle"
|
||||
end
|
||||
|
||||
trait :with_files do
|
||||
files { [Rack::Test::UploadedFile.new('spec/fixtures/files/contract.pdf', 'application/pdf')] }
|
||||
files do
|
||||
[
|
||||
Rack::Test::UploadedFile.new('spec/fixtures/files/contract.pdf', 'application/pdf'),
|
||||
Rack::Test::UploadedFile.new('spec/fixtures/files/audio.mp3', 'audio/mpeg'),
|
||||
Rack::Test::UploadedFile.new('spec/fixtures/files/video_file.mp4', 'video/mp4')
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
after(:build) do |broadcast, evaluator|
|
||||
|
||||
@@ -164,6 +164,21 @@ feature 'User managing broadcasts' do
|
||||
click_on add_file_button
|
||||
end
|
||||
|
||||
scenario 'manager user can click delete button next to the file and delete file', js: true do
|
||||
broadcast = create(:broadcast, :with_stream, :with_files, project: project)
|
||||
|
||||
visit project_broadcast_path(project, broadcast)
|
||||
|
||||
expect(page).to have_content delete_file_button, count: 3
|
||||
|
||||
accept_alert do
|
||||
first('a', text: delete_file_button).click
|
||||
end
|
||||
|
||||
expect(page).to have_content delete_file_button, count: 2
|
||||
expect(Broadcast.find(broadcast.id).files.count).to eq 2
|
||||
end
|
||||
|
||||
scenario 'visit multi-view broadcast page', js: true do
|
||||
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)
|
||||
@@ -198,6 +213,14 @@ feature 'User managing broadcasts' do
|
||||
expect(page).to have_content schedule_demo
|
||||
expect(page).not_to have_content create_stream
|
||||
end
|
||||
|
||||
scenario 'associate user does not see delete button next to the file', js: true do
|
||||
broadcast = create(:broadcast, :with_stream, :with_files, project: project)
|
||||
|
||||
visit project_broadcast_path(project, broadcast)
|
||||
|
||||
expect(page).to have_content delete_file_button, count: 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'When the user is account manager' do
|
||||
@@ -209,6 +232,21 @@ feature 'User managing broadcasts' do
|
||||
expect(page).to have_content schedule_demo
|
||||
expect(page).to have_content create_stream
|
||||
end
|
||||
|
||||
scenario 'account manager user can click delete button next to the file and delete file', js: true do
|
||||
broadcast = create(:broadcast, :with_stream, :with_files, project: project)
|
||||
|
||||
visit project_broadcast_path(project, broadcast)
|
||||
|
||||
expect(page).to have_content delete_file_button, count: 3
|
||||
|
||||
accept_alert do
|
||||
first('a', text: delete_file_button).click
|
||||
end
|
||||
|
||||
expect(page).to have_content delete_file_button, count: 2
|
||||
expect(Broadcast.find(broadcast.id).files.count).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -262,5 +300,9 @@ feature 'User managing broadcasts' do
|
||||
'Live stream is waiting to begin'
|
||||
end
|
||||
|
||||
def delete_file_button
|
||||
t 'broadcasts.file.actions.delete_file'
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user