Upstream sync

This commit is contained in:
Senad Uka
2020-07-14 14:10:30 +02:00
parent 35303cb570
commit 4c49a5db03
28 changed files with 407 additions and 29 deletions

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

@@ -6,8 +6,8 @@ class GenerateContractsZipJob < ApplicationJob
before_perform do |job| before_perform do |job|
@project = job.arguments.first @project = job.arguments.first
@download = job.arguments.second @download = job.arguments.second
release_type = job.arguments.third @release_type = job.arguments.third
@folder_name = "#{@project.name.parameterize}_#{get_release_name(release_type).gsub('_', '-')}" @folder_name = "#{@project.name.parameterize}_#{get_release_name(@release_type).gsub('_', '-')}"
@download.update!(name: @folder_name, status: :pending) @download.update!(name: @folder_name, status: :pending)
end end
@@ -20,6 +20,11 @@ class GenerateContractsZipJob < ApplicationJob
files.each do |attachment| files.each do |attachment|
zipfile.add(attachment, File.join("#{dir}/", attachment)) zipfile.add(attachment, File.join("#{dir}/", attachment))
end end
if @release_type.constantize.include?(CsvExportable)
csv_file = generate_csv releases
zipfile.get_output_stream("#{@folder_name}.csv") { |f| f.puts(csv_file) }
end
end end
@download.file.attach(io: File.open(zipfile_name), filename: "#{@folder_name}.zip") @download.file.attach(io: File.open(zipfile_name), filename: "#{@folder_name}.zip")
@@ -43,6 +48,19 @@ class GenerateContractsZipJob < ApplicationJob
private private
def generate_csv(releases)
release_class = @release_type.constantize
headers = release_class.csv_headers
CSV.generate(headers: true) do |csv|
csv << headers
releases.each do |release|
csv_row_data = release.to_csv_row
csv << csv_row_data
end
end
end
def get_release_name(release_type) def get_release_name(release_type)
release_type.constantize.model_name.plural release_type.constantize.model_name.plural
end end

View File

@@ -9,6 +9,13 @@ class AcquiredMediaRelease < ApplicationRecord
include Signable include Signable
include Syncable include Syncable
include PersonName include PersonName
include CsvExportable
class << self
def custom_csv_exportable_headers
%i[name file_infos_count]
end
end
has_many :file_infos, as: :releasable, dependent: :destroy has_many :file_infos, as: :releasable, dependent: :destroy
@@ -57,4 +64,8 @@ class AcquiredMediaRelease < ApplicationRecord
def uses_edl? def uses_edl?
true true
end end
def file_infos_count
file_infos.any? ? file_infos.size : I18n.t('acquired_media_releases.acquired_media_release.no_media')
end
end end

View File

@@ -15,6 +15,13 @@ class AppearanceRelease < ApplicationRecord
include SecondGuardianPhotoable include SecondGuardianPhotoable
include GuardianName include GuardianName
include SecondGuardianName include SecondGuardianName
include CsvExportable
class << self
def custom_csv_exportable_headers
%i[name contact_info]
end
end
has_one_attached :person_photo has_one_attached :person_photo

View File

@@ -0,0 +1,56 @@
# frozen_string_literal: true
module CsvExportable
extend ActiveSupport::Concern
COMMON_HEADERS = %i[notes tags signed_at].freeze
COMMON_VALUES = %w[clean_notes clean_tags signed_on].freeze
included do
class << self
def custom_csv_exportable_headers
[]
end
def csv_headers
headers = custom_csv_exportable_headers + COMMON_HEADERS
headers.map do |header|
I18n.t("#{model_name.plural}.index.table_headers.#{header}")
end
end
end
def to_csv_row
(self.class.custom_csv_exportable_headers + COMMON_VALUES).map do |function|
send(function)
end
end
private
def contact_info
contact_info = ''
contact_info += "#{person_address}; " if person_address.present?
contact_info += "P: #{person_phone}; " if person_phone.present?
contact_info += "E: #{person_email}" if person_email.present?
contact_info.delete_suffix '; '
end
def clean_notes
notes = ''
self.notes.order_by_recent.each do |note|
notes += "#{note.content}(#{note.email}), "
end
notes.delete_suffix ', '
end
def clean_tags
tags = ''
self.tags.each do |tag|
tags += "#{tag.name}, "
end
tags.delete_suffix ', '
end
end
end

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

@@ -10,6 +10,13 @@ class LocationRelease < ApplicationRecord
include Syncable include Syncable
include Taggable include Taggable
include PersonName include PersonName
include CsvExportable
class << self
def custom_csv_exportable_headers
%i[name address]
end
end
composed_of :address, composed_of :address,
mapping: [ mapping: [

View File

@@ -10,8 +10,15 @@ class MaterialRelease < ApplicationRecord
include Syncable include Syncable
include Taggable include Taggable
include PersonName include PersonName
include CsvExportable
composed_of :person_address,
class << self
def custom_csv_exportable_headers
%i[name]
end
end
composed_of :person_address,
class_name: "Address", class_name: "Address",
mapping: [ mapping: [
%w(person_address_street1 street1), %w(person_address_street1 street1),
@@ -30,15 +37,15 @@ class MaterialRelease < ApplicationRecord
validates :signature, attached: true validates :signature, attached: true
end end
searchable_on %i[ searchable_on %i[
name name
person_address_street1 person_address_street2 person_address_city person_address_state person_address_zip person_address_country person_address_street1 person_address_street2 person_address_city person_address_state person_address_zip person_address_country
] ]
def contact_person def contact_person
@contact_person ||= Contact.new(person_name, person_address, person_email, person_phone) @contact_person ||= Contact.new(person_name, person_address, person_email, person_phone)
end end
def minor? def minor?
false false
end end

View File

@@ -11,6 +11,13 @@ class MedicalRelease < ApplicationRecord
include SecondGuardianPhotoable include SecondGuardianPhotoable
include GuardianName include GuardianName
include SecondGuardianName include SecondGuardianName
include CsvExportable
class << self
def custom_csv_exportable_headers
%i[approved? name contact_info]
end
end
NUMBER_OF_CUSTOM_FIELDS = 15 NUMBER_OF_CUSTOM_FIELDS = 15

View File

@@ -9,6 +9,13 @@ class MiscRelease < ApplicationRecord
include PersonName include PersonName
include GuardianName include GuardianName
include GuardianPhotoable include GuardianPhotoable
include CsvExportable
class << self
def custom_csv_exportable_headers
%i[name contact_info]
end
end
NUMBER_OF_CUSTOM_FIELDS = 15 NUMBER_OF_CUSTOM_FIELDS = 15

View File

@@ -7,7 +7,14 @@ class MusicRelease < ApplicationRecord
include Searchable include Searchable
include Taggable include Taggable
include PersonName include PersonName
include CsvExportable
class << self
def custom_csv_exportable_headers
%i[name file_infos_count composers_count publishers_count]
end
end
has_many :file_infos, as: :releasable, dependent: :destroy has_many :file_infos, as: :releasable, dependent: :destroy
has_many :composers, dependent: :destroy has_many :composers, dependent: :destroy
has_many :publishers, dependent: :destroy has_many :publishers, dependent: :destroy
@@ -72,6 +79,18 @@ class MusicRelease < ApplicationRecord
false false
end end
def file_infos_count
file_infos.size
end
def composers_count
composers.size
end
def publishers_count
publishers.size
end
private private
def publisher_percentages_add_up_to_100 def publisher_percentages_add_up_to_100

View File

@@ -14,6 +14,13 @@ class TalentRelease < ApplicationRecord
include SecondGuardianPhotoable include SecondGuardianPhotoable
include GuardianName include GuardianName
include SecondGuardianName include SecondGuardianName
include CsvExportable
class << self
def custom_csv_exportable_headers
%i[name phone email]
end
end
composed_of :person_address, composed_of :person_address,
class_name: "Address", class_name: "Address",
@@ -86,6 +93,14 @@ class TalentRelease < ApplicationRecord
person_name person_name
end end
def phone
person_phone
end
def email
person_email
end
def filename_suffix def filename_suffix
"#{person_last_name} #{person_first_name}" "#{person_last_name} #{person_first_name}"
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

@@ -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

@@ -50,6 +50,7 @@ en:
empty: Acquired Media Releases will appear here empty: Acquired Media Releases will appear here
table_headers: table_headers:
file_infos_count: No. Files file_infos_count: No. Files
name: Name
notes: Notes notes: Notes
signed_at: Date Signed signed_at: Date Signed
tags: Tags tags: Tags
@@ -151,6 +152,8 @@ en:
empty: Appearance Releases will appear here empty: Appearance Releases will appear here
imported_appearance_release_missing_attachment: Person photo or contract missing for imported appearance release imported_appearance_release_missing_attachment: Person photo or contract missing for imported appearance release
table_headers: table_headers:
contact_info: Contact info
name: Name
notes: Notes notes: Notes
signed_at: Date Signed signed_at: Date Signed
tags: Tags tags: Tags
@@ -742,6 +745,7 @@ en:
empty: Location Releases will appear here empty: Location Releases will appear here
table_headers: table_headers:
address: Address address: Address
name: Name
notes: Notes notes: Notes
signed_at: Date Signed signed_at: Date Signed
tags: Tags tags: Tags
@@ -776,6 +780,7 @@ en:
search: Search search: Search
empty: Material Releases will appear here empty: Material Releases will appear here
table_headers: table_headers:
name: Name
notes: Notes notes: Notes
signed_at: Date Signed signed_at: Date Signed
tags: Tags tags: Tags
@@ -798,6 +803,9 @@ en:
empty: Medical releases will appear here empty: Medical releases will appear here
table_headers: table_headers:
approved: Approved approved: Approved
approved?: Approved
contact_info: Contact info
name: Person name
notes: Notes notes: Notes
signed_at: Date Signed signed_at: Date Signed
tags: Tags tags: Tags
@@ -815,6 +823,8 @@ en:
search: Search search: Search
empty: Misc Releases will appear here empty: Misc Releases will appear here
table_headers: table_headers:
contact_info: Contact info
name: Person name
notes: Notes notes: Notes
signed_at: Date Signed signed_at: Date Signed
tags: Tags tags: Tags
@@ -849,6 +859,7 @@ en:
table_headers: table_headers:
composers_count: No. Composers composers_count: No. Composers
file_infos_count: No. Files file_infos_count: No. Files
name: Name
notes: Notes notes: Notes
publishers_count: No. Publishers publishers_count: No. Publishers
signed_at: Date Signed signed_at: Date Signed
@@ -1245,7 +1256,10 @@ en:
search: Search search: Search
empty: Talent Releases will appear here empty: Talent Releases will appear here
table_headers: table_headers:
email: Email
name: Name
notes: Notes notes: Notes
phone: Phone
signed_at: Date Signed signed_at: Date Signed
tags: Tags tags: Tags
new: new:

View File

@@ -1,4 +1,14 @@
es: es:
acquired_media_releases:
acquired_media_release:
no_media: No Media (ES)
index:
table_headers:
file_infos_count: No. Files (ES)
name: Name (ES)
notes: Notes (ES)
signed_at: Date Signed (ES)
tags: Tags (ES)
activerecord: activerecord:
attributes: attributes:
appearance_release: appearance_release:
@@ -41,6 +51,12 @@ es:
heading: Person Photo (ES) heading: Person Photo (ES)
index: index:
imported_appearance_release_missing_attachment: Person photo or contract missing for imported appearance release (ES) imported_appearance_release_missing_attachment: Person photo or contract missing for imported appearance release (ES)
table_headers:
contact_info: ""
name: ""
notes: ""
signed_at: ""
tags: ""
shared: shared:
imported_appearance_release_contract_name: Contrato Importado imported_appearance_release_contract_name: Contrato Importado
imported_appearance_release_headshot_name: Retrato Importado imported_appearance_release_headshot_name: Retrato Importado
@@ -296,21 +312,57 @@ es:
form: form:
photos: photos:
dropzone_label: Tap to take a photo of the Property (optional) (ES) dropzone_label: Tap to take a photo of the Property (optional) (ES)
index:
table_headers:
address: Address (ES)
notes: Notes (ES)
signed_at: Date Signed (ES)
tags: Tags (ES)
material_releases: material_releases:
form: form:
photos: photos:
dropzone_label: Tap to take a photo of Licensed Material (optional) (ES) dropzone_label: Tap to take a photo of Licensed Material (optional) (ES)
index:
table_headers:
name: Name (ES)
notes: Notes (ES)
signed_at: Date Signed (ES)
tags: Tags (ES)
medical_releases: medical_releases:
custom_validation_errors: custom_validation_errors:
question_answer_is_required: answer is required (ES) question_answer_is_required: answer is required (ES)
index: index:
table_headers: table_headers:
approved: Approved (ES) approved: Approved (ES)
approved?: Approved (ES)
contact_info: Contact info (ES)
name: Person name (ES)
notes: Notes (ES)
signed_at: Date Signed (ES)
tags: Tags (ES)
medical_release: medical_release:
actions: actions:
review: Review (ES) review: Review (ES)
messages: messages:
approved_tooltip: "" approved_tooltip: ""
misc_releases:
index:
table_headers:
contact_info: Contact info (ES)
name: Person name (ES)
notes: Notes (ES)
signed_at: Date Signed (ES)
tags: Tags (ES)
music_releases:
index:
table_headers:
composers_count: No. Composers (ES)
file_infos_count: No. Files (ES)
name: Name (ES)
notes: Notes (ES)
publishers_count: No. Publishers (ES)
signed_at: Date Signed (ES)
tags: Tags (ES)
public: public:
appearance_releases: appearance_releases:
create: create:
@@ -415,6 +467,14 @@ es:
heading: Second Guardian Photo (ES) heading: Second Guardian Photo (ES)
guardian_photo: guardian_photo:
heading: Guardian Photo (ES) heading: Guardian Photo (ES)
index:
table_headers:
email: Email (ES)
name: Name (ES)
notes: Notes (ES)
phone: Phone (ES)
signed_at: Date Signed (ES)
tags: Tags (ES)
task_requests: task_requests:
create: create:
success_message: Your task request was successfully submitted. Thank you. A chat window will pop up on the lower right in a few seconds. (ES) success_message: Your task request was successfully submitted. Thank you. A chat window will pop up on the lower right in a few seconds. (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

@@ -9,6 +9,20 @@ SET xmloption = content;
SET client_min_messages = warning; SET client_min_messages = warning;
SET row_security = off; 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: - -- Name: fuzzystrmatch; Type: EXTENSION; Schema: -; Owner: -
-- --
@@ -494,7 +508,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 +644,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 +3922,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

@@ -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

@@ -11,7 +11,7 @@ describe GenerateContractsZipJob do
dir = Rails.root.join("spec", "fixtures", "files") dir = Rails.root.join("spec", "fixtures", "files")
files = ["contract.pdf", "AppearanceRelease.pdf"] files = ["contract.pdf", "AppearanceRelease.pdf"]
# Attachments in the test environment do not persist to cloud storage # Attachments in the test environment do not persist to cloud storage
# Therefore we want to stub calls to `open` with a cloud storage URL # Therefore we want to stub calls to `open` with a cloud storage URL
allow_any_instance_of(ReleaseContractCollectionService).to receive(:open).and_return(StringIO.new("file data")) allow_any_instance_of(ReleaseContractCollectionService).to receive(:open).and_return(StringIO.new("file data"))
allow_any_instance_of(ReleaseContractCollectionService).to receive(:build).and_yield(dir, files) allow_any_instance_of(ReleaseContractCollectionService).to receive(:build).and_yield(dir, files)
end end
@@ -35,6 +35,38 @@ describe GenerateContractsZipJob do
expect(download.file).to be_attached expect(download.file).to be_attached
end end
it "generates ZIP containing CSV file with all releases data for all release types" do
release_types = %w[AcquiredMediaRelease AppearanceRelease LocationRelease MaterialRelease MedicalRelease MiscRelease MusicRelease TalentRelease]
create_releases_for_all_types
release_types.each do |type|
lowercase_plural = type.constantize.model_name.plural
GenerateContractsZipJob.perform_now(project, download, type, project.public_send(lowercase_plural).ids)
generated_zip = download.file.blob.download
csv_file_name = "#{project.name.parameterize}_#{lowercase_plural.gsub('_', '-')}.csv"
Zip::InputStream.open(StringIO.new(generated_zip)) do |io|
while entry = io.get_next_entry
next unless entry.name == csv_file_name
csv_file = entry.get_input_stream.read
release_class = Object.const_get type
release_headers = release_class.csv_headers
release_headers.each do |header|
expect(csv_file).to match header
end
end
dummy_zip_file_name = "#{project.name.parameterize}_#{lowercase_plural.gsub('_', '-')}.zip"
if File.exist?(file_fixture(dummy_zip_file_name))
File.delete(file_fixture(dummy_zip_file_name))
end
end
end
end
context "When there are errors" do context "When there are errors" do
let(:error) { StandardError.new("Contracts or contract templates not found.") } let(:error) { StandardError.new("Contracts or contract templates not found.") }
@@ -42,10 +74,10 @@ describe GenerateContractsZipJob do
allow(ProjectsChannel).to receive(:broadcast_download_generation_update).with(download, I18n.t("contract_downloads.download.failure")) allow(ProjectsChannel).to receive(:broadcast_download_generation_update).with(download, I18n.t("contract_downloads.download.failure"))
allow_any_instance_of(ReleaseContractCollectionService).to receive(:build).and_raise(StandardError, "Contracts or contract templates not found") allow_any_instance_of(ReleaseContractCollectionService).to receive(:build).and_raise(StandardError, "Contracts or contract templates not found")
end end
it "updates status to 'failure' and sends user a notification" do it "updates status to 'failure' and sends user a notification" do
GenerateContractsZipJob.perform_now(project, download, "AppearanceRelease", project.appearance_releases.ids) GenerateContractsZipJob.perform_now(project, download, "AppearanceRelease", project.appearance_releases.ids)
expect(download.status).to eq "failure" expect(download.status).to eq "failure"
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(download, I18n.t("contract_downloads.download.failure")) expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(download, I18n.t("contract_downloads.download.failure"))
end end
@@ -56,6 +88,21 @@ describe GenerateContractsZipJob do
# Delete the file created in fixture. # Delete the file created in fixture.
# Or the tests will fail on next run due to already existing files in existing zip. # Or the tests will fail on next run due to already existing files in existing zip.
path = Rails.root.join("spec", "fixtures", "files") path = Rails.root.join("spec", "fixtures", "files")
File.delete("#{path}/my-video-project_appearance-releases.zip") if File.exists? "#{path}/my-video-project_appearance-releases.zip" if File.exists? "#{path}/my-video-project_appearance-releases.zip"
File.delete("#{path}/my-video-project_appearance-releases.zip")
end
end
private
def create_releases_for_all_types
create(:acquired_media_release_with_contract_template, :native, project: project)
create(:appearance_release_with_contract_template, :native, project: project, person_name: "John Doe")
create(:location_release_with_contract_template, :native, project: project)
create(:material_release_with_contract_template, :native, project: project)
create(:medical_release_with_contract_template, :native, project: project)
create(:misc_release_with_contract_template, :native, project: project)
create(:music_release_with_contract_template, project: project)
create(:talent_release_with_contract_template, :native, project: project)
end end
end end

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