Compare commits

..

3 Commits

Author SHA1 Message Date
Bilal
062e81fed3 update label 2020-07-15 12:34:02 +02:00
Senad Uka
7f49f31ebf Master sync 2020-07-15 11:58:34 +02:00
Senad Uka
4c49a5db03 Upstream sync 2020-07-14 14:10:30 +02:00
23 changed files with 166 additions and 24 deletions

View File

@@ -33,6 +33,11 @@ class BroadcastsController < ApplicationController
end end
def update def update
unless params.has_key?(:broadcast)
@broadcast.regenerate_token
redirect_to([@project, @broadcast], notice: t('.reset_notice')) and return
end
@broadcast.update(broadcast_params) @broadcast.update(broadcast_params)
@files = @broadcast.files.order("created_at DESC").paginate(page: 1) @files = @broadcast.files.order("created_at DESC").paginate(page: 1)

View File

@@ -66,7 +66,7 @@ class ContractTemplatesController < ApplicationController
:signature_legal_text, :fee, :signature_legal_text, :fee,
:applicable_medium_id, :applicable_medium_text, :applicable_medium_id, :applicable_medium_text,
:territory_id, :territory_text, :territory_id, :territory_text,
:term_id, :term_text, :term_id, :term_text, :accessibility,
:restriction_id, :restriction_text, :restriction_id, :restriction_text,
:question_1_text, :question_2_text, :question_1_text, :question_2_text,
:question_3_text, :question_4_text, :question_3_text, :question_4_text,

View File

@@ -28,8 +28,9 @@ class StreamNotificationsController < ApplicationController
asset_uid = notification.dig(:object, :id) asset_uid = notification.dig(:object, :id)
playback_uid = notification.dig(:data, :playback_ids, 0, :id) playback_uid = notification.dig(:data, :playback_ids, 0, :id)
file_name = notification.dig(:data, :static_renditions, :files, -1, :name) file_name = notification.dig(:data, :static_renditions, :files, -1, :name)
duration = notification.dig(:data, :duration)
recording = @broadcast.broadcast_recordings.create!(asset_uid: asset_uid, asset_playback_uid: playback_uid, file_name: file_name) recording = @broadcast.broadcast_recordings.create!(asset_uid: asset_uid, asset_playback_uid: playback_uid, file_name: file_name, duration: duration)
recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page]) recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page])
link = helpers.link_to(recording.broadcast_name.titleize, recording.download_url, target: "_blank") link = helpers.link_to(recording.broadcast_name.titleize, recording.download_url, target: "_blank")

View File

@@ -43,6 +43,8 @@ class ContractTemplate < ApplicationRecord
scope :non_archived, -> { where(archived_at: nil) } scope :non_archived, -> { where(archived_at: nil) }
scope :order_by_name, -> { order(:name) } scope :order_by_name, -> { order(:name) }
enum accessibility: [:public_template, :private_template]
def fee? def fee?
!fee.zero? !fee.zero?
end end
@@ -66,4 +68,10 @@ class ContractTemplate < ApplicationRecord
def has_questionnaire? def has_questionnaire?
(1..NUMBER_OF_CUSTOM_FIELDS).any? { |n| public_send("question_#{n}_text").presence } (1..NUMBER_OF_CUSTOM_FIELDS).any? { |n| public_send("question_#{n}_text").presence }
end end
def attributes
result = super()
result[:signature_legal_text] = signature_legal_text.as_json
result
end
end end

View File

@@ -3,8 +3,10 @@ class ContractTemplatePolicy < ApplicationPolicy
def resolve def resolve
if user.account_manager? if user.account_manager?
scope.left_outer_joins(:project).where(projects: {account: user.account}) scope.left_outer_joins(:project).where(projects: {account: user.account})
else elsif user.manager?
scope.left_outer_joins(project: :project_memberships).where(project_memberships: { user_id: user.id }) scope.left_outer_joins(project: :project_memberships).where(project_memberships: { user_id: user.id })
else
scope.public_template.left_outer_joins(project: :project_memberships).where(project_memberships: { user_id: user.id })
end end
end end
end end

View File

@@ -102,6 +102,7 @@
<i class="fa fa-clipboard"></i> <i class="fa fa-clipboard"></i>
Copy URL Copy URL
</button> </button>
<%= link_to t('.actions.reset_url'), [@project, @broadcast], method: :patch, class: "btn btn-danger" %>
</div> </div>
<% else %> <% else %>
<input type="text" class="form-control" value="<%= broadcast_url(@broadcast.token) %>" readonly> <input type="text" class="form-control" value="<%= broadcast_url(@broadcast.token) %>" readonly>
@@ -110,6 +111,7 @@
<i class="fa fa-clipboard"></i> <i class="fa fa-clipboard"></i>
Copy URL Copy URL
</button> </button>
<%= link_to t('.actions.reset_url'), [@project, @broadcast], method: :patch, class: "btn btn-danger" %>
</div> </div>
<% end %> <% end %>
</div> </div>

View File

@@ -4,6 +4,10 @@
<%= form.text_field :name, wrapper_class: "col-sm-6" %> <%= form.text_field :name, wrapper_class: "col-sm-6" %>
<%= form.select :release_type, options_for_release_type_select(project, @release_type), { wrapper_class: "col-sm-6" }, data: { toggle: "collapse-select", target_show_values_mapping: { "#guardian_clause": %w(appearance talent misc medical), "#fee_field": %w(appearance talent location material acquired_media), "#exploitable_rights_fields": %w(appearance talent location material acquired_media), "#custom_fields": %w(medical misc) } }, class: "form-control custom-select" %> <%= form.select :release_type, options_for_release_type_select(project, @release_type), { wrapper_class: "col-sm-6" }, data: { toggle: "collapse-select", target_show_values_mapping: { "#guardian_clause": %w(appearance talent misc medical), "#fee_field": %w(appearance talent location material acquired_media), "#exploitable_rights_fields": %w(appearance talent location material acquired_media), "#custom_fields": %w(medical misc) } }, class: "form-control custom-select" %>
</div> </div>
<div class="form-row mb-3">
<%= form.radio_button :accessibility, :public_template, label: "Public", wrapper_class: "mr-3" %>
<%= form.radio_button :accessibility, :private_template, label: "Private" %>
</div>
<div class="form-row" id="fee_field"> <div class="form-row" id="fee_field">
<%= form.number_field :fee, min:"0", max:"99999999", step: "0.01", prepend: "$", wrapper_class: "col-sm-6" %> <%= form.number_field :fee, min:"0", max:"99999999", step: "0.01", prepend: "$", wrapper_class: "col-sm-6" %>
</div> </div>

View File

@@ -7,7 +7,7 @@
<dl> <dl>
<%= description_list_pair t('.description_labels.producer'), releasable.project.account.name %> <%= description_list_pair t('.description_labels.producer'), releasable.project.account.name %>
<%= description_list_pair t('.description_labels.production'), releasable.project.name %> <%= description_list_pair t('.description_labels.production'), releasable.project.name %>
<%= description_list_pair t('.description_labels.employee_issued_to'), releasable.name %> <%= description_list_pair t('.description_labels.issued_to'), releasable.name %>
<%= description_list_pair t('.description_labels.issued_by'), releasable.approved_by_user_name %> <%= description_list_pair t('.description_labels.issued_by'), releasable.approved_by_user_name %>
<%= description_list_pair t('.description_labels.date_issued'), releasable.approved_at %> <%= description_list_pair t('.description_labels.date_issued'), releasable.approved_at %>
</dl> </dl>

View File

@@ -217,6 +217,9 @@ en:
new: new:
heading: heading:
Create Live Stream Create Live Stream
show:
actions:
reset_url: Reset URL
splash: splash:
actions: actions:
book_demo: Schedule a Demo book_demo: Schedule a Demo
@@ -235,6 +238,8 @@ en:
share_stream: Share live stream link with clients share_stream: Share live stream link with clients
stream_from_mobile_app: Stream from ME Suite Mobile app, or via a professional camera stream_from_mobile_app: Stream from ME Suite Mobile app, or via a professional camera
stream_multiple_cameras: Stream multiple cameras at one time stream_multiple_cameras: Stream multiple cameras at one time
update:
reset_notice: The Share URL has been reset, and the previous URL will no longer work. Please click "Copy URL" and share it again with those who you want to have access to this live stream
bulk_taggings: bulk_taggings:
new_bulk_tag_modal: new_bulk_tag_modal:
submit: Add submit: Add
@@ -301,8 +306,8 @@ en:
for_office_use_only: for_office_use_only:
description_labels: description_labels:
date_issued: Date Issued date_issued: Date Issued
employee_issued_to: Employee Issued To
issued_by: Issued By issued_by: Issued By
issued_to: Issued To
producer: Producer producer: Producer
production: Production production: Production
heading: For Office Use Only heading: For Office Use Only

View File

@@ -81,6 +81,9 @@ es:
do_not_copy_warning: "Do not copy (ES)" do_not_copy_warning: "Do not copy (ES)"
serial_number_label: "Serial Number (ES)" serial_number_label: "Serial Number (ES)"
broadcasts: broadcasts:
show:
actions:
reset_url: Reset URL (ES)
splash: splash:
actions: actions:
book_demo: Schedule a Demo book_demo: Schedule a Demo
@@ -99,6 +102,8 @@ es:
share_stream: Share live stream link with clients share_stream: Share live stream link with clients
stream_from_mobile_app: Stream from ME Suite Mobile app, or via a professional camera stream_from_mobile_app: Stream from ME Suite Mobile app, or via a professional camera
stream_multiple_cameras: Stream multiple cameras at one time stream_multiple_cameras: Stream multiple cameras at one time
update:
reset_notice: The Share URL has been reset, and the previous URL will no longer work. Please click "Copy URL" and share it again with those who you want to have access to this live stream
contract_templates: contract_templates:
blank_contracts: blank_contracts:
create: create:
@@ -133,8 +138,8 @@ es:
for_office_use_only: for_office_use_only:
description_labels: description_labels:
date_issued: Date Issued (ES) date_issued: Date Issued (ES)
employee_issued_to: Employee Issued To (ES)
issued_by: Issued By (ES) issued_by: Issued By (ES)
issued_to: Issued To (ES)
producer: Producer (ES) producer: Producer (ES)
production: Production (ES) production: Production (ES)
heading: For Office Use Only (ES) heading: For Office Use Only (ES)

View File

@@ -0,0 +1,18 @@
class AddDurationToBroadcastRecordings < ActiveRecord::DataMigration
def up
recordings = BroadcastRecording.where(duration: nil)
client = MuxRuby::AssetsApi.new
recordings.each do |recording|
begin
response = client.get_asset(recording.asset_uid)
duration = response.data.duration
recording.update(duration: duration)
rescue MuxRuby::ApiError => e
Rails.logger.error("Failed to update duration for broadcast recording with id #{recording.id}\n" + e.message)
end
sleep(1)
end
end
end

View File

@@ -0,0 +1,5 @@
class AddAccessibilityToContractTemplates < ActiveRecord::Migration[6.0]
def change
add_column :contract_templates, :accessibility, :integer, default: 0
end
end

View File

@@ -0,0 +1,5 @@
class AddDurationToBroadcastRecordings < ActiveRecord::Migration[6.0]
def change
add_column :broadcast_recordings, :duration, :float
end
end

View File

@@ -494,7 +494,8 @@ CREATE TABLE public.broadcast_recordings (
asset_playback_uid character varying NOT NULL, asset_playback_uid character varying NOT NULL,
file_name character varying NOT NULL, file_name character varying NOT NULL,
created_at timestamp(6) without time zone NOT NULL, created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL updated_at timestamp(6) without time zone NOT NULL,
duration double precision
); );
@@ -629,7 +630,8 @@ CREATE TABLE public.contract_templates (
question_12_text text, question_12_text text,
question_13_text text, question_13_text text,
question_14_text text, question_14_text text,
question_15_text text question_15_text text,
accessibility integer DEFAULT 0
); );
@@ -3906,6 +3908,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200622180507'), ('20200622180507'),
('20200625144713'), ('20200625144713'),
('20200702152130'), ('20200702152130'),
('20200707155717'); ('20200707155717'),
('20200709120630'),
('20200712181139');

View File

@@ -30,6 +30,21 @@ RSpec.describe Api::ContractTemplatesController, type: :controller do
expect(response).to be_successful expect(response).to be_successful
end end
it 'returns electronic signature legal text when present' do
ct = create(:contract_template, name: 'ct1', project_id: project.id)
ct.signature_legal_text = "some electronic signature legal text"
ct.save
sign_in_to_api(current_user)
get :show, params: { id: ct.id }
expect(response).to be_successful
expect(response.body).to include("signature_legal_text")
expect(response.body).to include(ct.signature_legal_text.body.as_json)
end
end end
private private

View File

@@ -127,9 +127,16 @@ RSpec.describe Api::SyncController, type: :controller do
get :index get :index
medical_releases = attributes_for_type('medical_releases') medical_releases = attributes_for_type('medical_releases')
expect(medical_releases.first).to include('id') expect(medical_releases.first).to include('id')
end end
it 'contains signature legal text for contract templates' do
create_default_data_with_signature_legal_text
get :index
contract_templates = attributes_for_type('contract_templates')
expect(contract_templates.first).to include('signature_legal_text')
expect(contract_templates.first['signature_legal_text']).to eq ContractTemplate.first.signature_legal_text.as_json
end
end end
private private
@@ -149,6 +156,13 @@ RSpec.describe Api::SyncController, type: :controller do
create(:appearance_release, :minor_with_guardian_photo, project: project) create(:appearance_release, :minor_with_guardian_photo, project: project)
end end
def create_default_data_with_signature_legal_text
create_default_data
ct = create(:contract_template, name: "with signature legal text", project: Project.first)
ct.signature_legal_text = "legal text example"
ct.save
end
def response_body_json def response_body_json
JSON.parse(response.body) JSON.parse(response.body)
end end

View File

@@ -203,6 +203,15 @@ RSpec.describe BroadcastsController, type: :controller do
expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates) expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates)
end end
it "regenerates token if #update is called without broadcast param" do
old_token = broadcast.token
patch :update, params: { project_id: project.id, id: broadcast.id }
expect(response).to redirect_to [project, broadcast]
expect(flash.notice).to eq token_reset_notice
expect(Broadcast.last.token).not_to eq old_token
end
end end
describe "#destroy" do describe "#destroy" do
@@ -252,4 +261,8 @@ RSpec.describe BroadcastsController, type: :controller do
def create_stream def create_stream
t 'broadcasts.splash.actions.create_stream' t 'broadcasts.splash.actions.create_stream'
end end
def token_reset_notice
t 'broadcasts.update.reset_notice'
end
end end

View File

@@ -7,6 +7,7 @@ FactoryBot.define do
body "This is a test contract template." body "This is a test contract template."
guardian_clause "Is the signer a minor?" guardian_clause "Is the signer a minor?"
fee "$0.00" fee "$0.00"
accessibility "public_template"
trait :archived do trait :archived do
archived_at Time.zone.now archived_at Time.zone.now

View File

@@ -49,12 +49,18 @@ FactoryBot.define do
predefined_client_name "nat_geo" predefined_client_name "nat_geo"
end end
factory :project_with_contract_template do factory :project_with_contract_template_public do
after(:build) do |project, _| after(:build) do |project, _|
project.contract_templates << build(:contract_template, project: nil) project.contract_templates << build(:contract_template, project: nil)
end end
end end
factory :project_with_contract_template_private do
after(:build) do |project, _|
project.contract_templates << build(:contract_template, project: nil, accessibility: "private_template")
end
end
factory :project_with_directories do factory :project_with_directories do
after(:build) do |project, _| after(:build) do |project, _|
project.directories << build(:directory, project: nil, name: "Shared") project.directories << build(:directory, project: nil, name: "Shared")

View File

@@ -63,6 +63,21 @@ feature 'User managing broadcasts' do
expect(page).to have_content(recording.download_file_name) expect(page).to have_content(recording.download_file_name)
end end
scenario 'Clicking Reset URL regenerates broadcast token' do
broadcast = create(:broadcast, :with_stream, :with_files, project: project)
old_token = broadcast.token
visit project_broadcast_path(project, broadcast)
expect(page).to have_content reset_url
expect(page).to have_xpath "//input[@readonly][@value='#{broadcast_url(old_token)}']"
click_link reset_url
expect(Broadcast.last.token).not_to eq old_token
expect(page).to have_xpath "//input[@readonly][@value='#{broadcast_url(Broadcast.last.token)}']"
expect(page).to have_content token_reset_notice
end
scenario 'user can go back and forth between live session and previous sessions', js: true do scenario 'user can go back and forth between live session and previous sessions', js: true do
broadcast = create(:broadcast, :with_stream, :with_files, project: project) broadcast = create(:broadcast, :with_stream, :with_files, project: project)
recording = create(:broadcast_recording, broadcast: broadcast) recording = create(:broadcast_recording, broadcast: broadcast)
@@ -189,4 +204,12 @@ feature 'User managing broadcasts' do
def create_stream def create_stream
t 'broadcasts.splash.actions.create_stream' t 'broadcasts.splash.actions.create_stream'
end end
def reset_url
t 'broadcasts.show.actions.reset_url'
end
def token_reset_notice
t 'broadcasts.update.reset_notice'
end
end end

View File

@@ -260,7 +260,7 @@ feature "User managing medical releases" do
expect(pdf_body).to have_content for_office_use_only.upcase expect(pdf_body).to have_content for_office_use_only.upcase
expect(pdf_body).to have_content producer_label expect(pdf_body).to have_content producer_label
expect(pdf_body).to have_content production_label expect(pdf_body).to have_content production_label
expect(pdf_body).to have_content employee_issued_to_label expect(pdf_body).to have_content issued_to_label
expect(pdf_body).to have_content issued_by_label expect(pdf_body).to have_content issued_by_label
expect(pdf_body).to have_content date_issued expect(pdf_body).to have_content date_issued
expect(pdf_body).to have_content 'Big Joe' expect(pdf_body).to have_content 'Big Joe'
@@ -282,7 +282,7 @@ feature "User managing medical releases" do
expect(pdf_body).not_to have_content for_office_use_only.upcase expect(pdf_body).not_to have_content for_office_use_only.upcase
expect(pdf_body).not_to have_content producer_label expect(pdf_body).not_to have_content producer_label
expect(pdf_body).not_to have_content production_label expect(pdf_body).not_to have_content production_label
expect(pdf_body).not_to have_content employee_issued_to_label expect(pdf_body).not_to have_content issued_to_label
expect(pdf_body).not_to have_content issued_by_label expect(pdf_body).not_to have_content issued_by_label
expect(pdf_body).not_to have_content date_issued expect(pdf_body).not_to have_content date_issued
expect(pdf_body).not_to have_content 'Big Joe' expect(pdf_body).not_to have_content 'Big Joe'
@@ -580,8 +580,8 @@ feature "User managing medical releases" do
t 'contracts.for_office_use_only.description_labels.production' t 'contracts.for_office_use_only.description_labels.production'
end end
def employee_issued_to_label def issued_to_label
t 'contracts.for_office_use_only.description_labels.employee_issued_to' t 'contracts.for_office_use_only.description_labels.issued_to'
end end
def issued_by_label def issued_by_label

View File

@@ -36,7 +36,7 @@ RSpec.describe Project, type: :model do
describe "#import_contract_templates" do describe "#import_contract_templates" do
it "imports contract templates from other projects within the account" do it "imports contract templates from other projects within the account" do
existing_project = create(:project_with_contract_template) existing_project = create(:project_with_contract_template_public)
new_project = create(:project, name: "New Project", account: existing_project.account) new_project = create(:project, name: "New Project", account: existing_project.account)
expect { expect {

View File

@@ -75,14 +75,17 @@ describe ContractTemplatePolicy do
end end
permissions ".scope" do permissions ".scope" do
let!(:member_project) do let!(:member_project_public_template) do
create(:project_with_contract_template, name: "Member Project", members: user, account: account) create(:project_with_contract_template_public, name: "Member Project Public Template", members: user, account: account)
end
let!(:member_project_private_template) do
create(:project_with_contract_template_private, name: "Member Project Private Template", members: user, account: account)
end end
let!(:non_member_project) do let!(:non_member_project) do
create(:project_with_contract_template, name: "Non-Member Project", account: account) create(:project_with_contract_template_public, name: "Non-Member Project", account: account)
end end
let!(:outside_project) do let!(:outside_project) do
create(:project_with_contract_template, name: "Outside Project", account: build(:account)) create(:project_with_contract_template_public, name: "Outside Project", account: build(:account))
end end
let(:account) { build(:account) } let(:account) { build(:account) }
@@ -93,7 +96,8 @@ describe ContractTemplatePolicy do
context "for an account manager" do context "for an account manager" do
let(:user) { create(:user, :account_manager, primary_account: account)} let(:user) { create(:user, :account_manager, primary_account: account)}
it { is_expected.to include(member_project.contract_templates.first) } it { is_expected.to include(member_project_public_template.contract_templates.first) }
it { is_expected.to include(member_project_private_template.contract_templates.first) }
it { is_expected.to include(non_member_project.contract_templates.first) } it { is_expected.to include(non_member_project.contract_templates.first) }
it { is_expected.not_to include(outside_project.contract_templates.first) } it { is_expected.not_to include(outside_project.contract_templates.first) }
end end
@@ -101,15 +105,17 @@ describe ContractTemplatePolicy do
context "for manager" do context "for manager" do
let(:user) { create(:user, :manager, primary_account: account) } let(:user) { create(:user, :manager, primary_account: account) }
it { is_expected.to include(member_project.contract_templates.first) } it { is_expected.to include(member_project_public_template.contract_templates.first) }
it { is_expected.to include(member_project_private_template.contract_templates.first) }
it { is_expected.not_to include(non_member_project.contract_templates.first) } it { is_expected.not_to include(non_member_project.contract_templates.first) }
it { is_expected.not_to include(outside_project.contract_templates.first) } it { is_expected.not_to include(outside_project.contract_templates.first) }
end end
context "for associate" do context "for associate" do
let(:user) { create(:user, :associate, primary_account: account) } let(:user) { create(:user, :associate, primary_account: account) }
it { is_expected.to include(member_project.contract_templates.first) } it { is_expected.to include(member_project_public_template.contract_templates.first) }
it { is_expected.not_to include(member_project_private_template.contract_templates.first) }
it { is_expected.not_to include(non_member_project.contract_templates.first) } it { is_expected.not_to include(non_member_project.contract_templates.first) }
it { is_expected.not_to include(outside_project.contract_templates.first) } it { is_expected.not_to include(outside_project.contract_templates.first) }
end end