From 4c49a5db03e07d82b871dbf731fa5b3535a33982 Mon Sep 17 00:00:00 2001 From: Senad Uka Date: Tue, 14 Jul 2020 14:10:30 +0200 Subject: [PATCH] Upstream sync --- .../contract_templates_controller.rb | 2 +- .../stream_notifications_controller.rb | 3 +- app/jobs/generate_contracts_zip_job.rb | 22 ++++++- app/models/acquired_media_release.rb | 11 ++++ app/models/appearance_release.rb | 7 +++ app/models/concerns/csv_exportable.rb | 56 +++++++++++++++++ app/models/contract_template.rb | 8 +++ app/models/location_release.rb | 7 +++ app/models/material_release.rb | 17 ++++-- app/models/medical_release.rb | 7 +++ app/models/misc_release.rb | 7 +++ app/models/music_release.rb | 21 ++++++- app/models/talent_release.rb | 15 +++++ app/policies/contract_template_policy.rb | 4 +- app/views/contract_templates/_form.html.erb | 4 ++ config/locales/en.yml | 14 +++++ config/locales/es.yml | 60 +++++++++++++++++++ ...01_add_duration_to_broadcast_recordings.rb | 18 ++++++ ...add_accessibility_to_contract_templates.rb | 5 ++ ...39_add_duration_to_broadcast_recordings.rb | 5 ++ db/structure.sql | 24 +++++++- .../api/contract_templates_controller_spec.rb | 15 +++++ spec/controllers/api/sync_controller_spec.rb | 16 ++++- spec/factories/contract_templates.rb | 1 + spec/factories/projects.rb | 8 ++- spec/jobs/generate_contracts_zip_job_spec.rb | 55 +++++++++++++++-- spec/models/project_spec.rb | 2 +- .../policies/contract_template_policy_spec.rb | 22 ++++--- 28 files changed, 407 insertions(+), 29 deletions(-) create mode 100644 app/models/concerns/csv_exportable.rb create mode 100644 db/data_migrations/20200712192301_add_duration_to_broadcast_recordings.rb create mode 100644 db/migrate/20200709120630_add_accessibility_to_contract_templates.rb create mode 100644 db/migrate/20200712181139_add_duration_to_broadcast_recordings.rb diff --git a/app/controllers/contract_templates_controller.rb b/app/controllers/contract_templates_controller.rb index 60d65d2..8e70811 100644 --- a/app/controllers/contract_templates_controller.rb +++ b/app/controllers/contract_templates_controller.rb @@ -66,7 +66,7 @@ class ContractTemplatesController < ApplicationController :signature_legal_text, :fee, :applicable_medium_id, :applicable_medium_text, :territory_id, :territory_text, - :term_id, :term_text, + :term_id, :term_text, :accessibility, :restriction_id, :restriction_text, :question_1_text, :question_2_text, :question_3_text, :question_4_text, diff --git a/app/controllers/stream_notifications_controller.rb b/app/controllers/stream_notifications_controller.rb index 12b8ee2..ce76ff6 100644 --- a/app/controllers/stream_notifications_controller.rb +++ b/app/controllers/stream_notifications_controller.rb @@ -28,8 +28,9 @@ class StreamNotificationsController < ApplicationController asset_uid = notification.dig(:object, :id) playback_uid = notification.dig(:data, :playback_ids, 0, :id) 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]) link = helpers.link_to(recording.broadcast_name.titleize, recording.download_url, target: "_blank") diff --git a/app/jobs/generate_contracts_zip_job.rb b/app/jobs/generate_contracts_zip_job.rb index 865a5ea..65bc376 100644 --- a/app/jobs/generate_contracts_zip_job.rb +++ b/app/jobs/generate_contracts_zip_job.rb @@ -6,8 +6,8 @@ class GenerateContractsZipJob < ApplicationJob before_perform do |job| @project = job.arguments.first @download = job.arguments.second - release_type = job.arguments.third - @folder_name = "#{@project.name.parameterize}_#{get_release_name(release_type).gsub('_', '-')}" + @release_type = job.arguments.third + @folder_name = "#{@project.name.parameterize}_#{get_release_name(@release_type).gsub('_', '-')}" @download.update!(name: @folder_name, status: :pending) end @@ -20,6 +20,11 @@ class GenerateContractsZipJob < ApplicationJob files.each do |attachment| zipfile.add(attachment, File.join("#{dir}/", attachment)) 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 @download.file.attach(io: File.open(zipfile_name), filename: "#{@folder_name}.zip") @@ -43,6 +48,19 @@ class GenerateContractsZipJob < ApplicationJob 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) release_type.constantize.model_name.plural end diff --git a/app/models/acquired_media_release.rb b/app/models/acquired_media_release.rb index 6a12d35..8b7a7b0 100644 --- a/app/models/acquired_media_release.rb +++ b/app/models/acquired_media_release.rb @@ -9,6 +9,13 @@ class AcquiredMediaRelease < ApplicationRecord include Signable include Syncable 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 @@ -57,4 +64,8 @@ class AcquiredMediaRelease < ApplicationRecord def uses_edl? true end + + def file_infos_count + file_infos.any? ? file_infos.size : I18n.t('acquired_media_releases.acquired_media_release.no_media') + end end diff --git a/app/models/appearance_release.rb b/app/models/appearance_release.rb index 9a750a7..c9bb4c0 100644 --- a/app/models/appearance_release.rb +++ b/app/models/appearance_release.rb @@ -15,6 +15,13 @@ class AppearanceRelease < ApplicationRecord include SecondGuardianPhotoable include GuardianName include SecondGuardianName + include CsvExportable + + class << self + def custom_csv_exportable_headers + %i[name contact_info] + end + end has_one_attached :person_photo diff --git a/app/models/concerns/csv_exportable.rb b/app/models/concerns/csv_exportable.rb new file mode 100644 index 0000000..4619e86 --- /dev/null +++ b/app/models/concerns/csv_exportable.rb @@ -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 diff --git a/app/models/contract_template.rb b/app/models/contract_template.rb index 8922bde..ba2ce3d 100644 --- a/app/models/contract_template.rb +++ b/app/models/contract_template.rb @@ -43,6 +43,8 @@ class ContractTemplate < ApplicationRecord scope :non_archived, -> { where(archived_at: nil) } scope :order_by_name, -> { order(:name) } + enum accessibility: [:public_template, :private_template] + def fee? !fee.zero? end @@ -66,4 +68,10 @@ class ContractTemplate < ApplicationRecord def has_questionnaire? (1..NUMBER_OF_CUSTOM_FIELDS).any? { |n| public_send("question_#{n}_text").presence } end + + def attributes + result = super() + result[:signature_legal_text] = signature_legal_text.as_json + result + end end diff --git a/app/models/location_release.rb b/app/models/location_release.rb index a5b6a02..1e49d73 100644 --- a/app/models/location_release.rb +++ b/app/models/location_release.rb @@ -10,6 +10,13 @@ class LocationRelease < ApplicationRecord include Syncable include Taggable include PersonName + include CsvExportable + + class << self + def custom_csv_exportable_headers + %i[name address] + end + end composed_of :address, mapping: [ diff --git a/app/models/material_release.rb b/app/models/material_release.rb index 56d45ee..dc5380e 100644 --- a/app/models/material_release.rb +++ b/app/models/material_release.rb @@ -10,8 +10,15 @@ class MaterialRelease < ApplicationRecord include Syncable include Taggable include PersonName - - composed_of :person_address, + include CsvExportable + + class << self + def custom_csv_exportable_headers + %i[name] + end + end + + composed_of :person_address, class_name: "Address", mapping: [ %w(person_address_street1 street1), @@ -30,15 +37,15 @@ class MaterialRelease < ApplicationRecord validates :signature, attached: true end - searchable_on %i[ - name + searchable_on %i[ + name person_address_street1 person_address_street2 person_address_city person_address_state person_address_zip person_address_country ] def contact_person @contact_person ||= Contact.new(person_name, person_address, person_email, person_phone) end - + def minor? false end diff --git a/app/models/medical_release.rb b/app/models/medical_release.rb index 996bfc5..e037ef5 100644 --- a/app/models/medical_release.rb +++ b/app/models/medical_release.rb @@ -11,6 +11,13 @@ class MedicalRelease < ApplicationRecord include SecondGuardianPhotoable include GuardianName include SecondGuardianName + include CsvExportable + + class << self + def custom_csv_exportable_headers + %i[approved? name contact_info] + end + end NUMBER_OF_CUSTOM_FIELDS = 15 diff --git a/app/models/misc_release.rb b/app/models/misc_release.rb index f9437dd..2679542 100644 --- a/app/models/misc_release.rb +++ b/app/models/misc_release.rb @@ -9,6 +9,13 @@ class MiscRelease < ApplicationRecord include PersonName include GuardianName include GuardianPhotoable + include CsvExportable + + class << self + def custom_csv_exportable_headers + %i[name contact_info] + end + end NUMBER_OF_CUSTOM_FIELDS = 15 diff --git a/app/models/music_release.rb b/app/models/music_release.rb index 29fd426..b324b9f 100644 --- a/app/models/music_release.rb +++ b/app/models/music_release.rb @@ -7,7 +7,14 @@ class MusicRelease < ApplicationRecord include Searchable include Taggable 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 :composers, dependent: :destroy has_many :publishers, dependent: :destroy @@ -72,6 +79,18 @@ class MusicRelease < ApplicationRecord false end + def file_infos_count + file_infos.size + end + + def composers_count + composers.size + end + + def publishers_count + publishers.size + end + private def publisher_percentages_add_up_to_100 diff --git a/app/models/talent_release.rb b/app/models/talent_release.rb index 8ca4dbe..f507ba7 100644 --- a/app/models/talent_release.rb +++ b/app/models/talent_release.rb @@ -14,6 +14,13 @@ class TalentRelease < ApplicationRecord include SecondGuardianPhotoable include GuardianName include SecondGuardianName + include CsvExportable + + class << self + def custom_csv_exportable_headers + %i[name phone email] + end + end composed_of :person_address, class_name: "Address", @@ -86,6 +93,14 @@ class TalentRelease < ApplicationRecord person_name end + def phone + person_phone + end + + def email + person_email + end + def filename_suffix "#{person_last_name} #{person_first_name}" end diff --git a/app/policies/contract_template_policy.rb b/app/policies/contract_template_policy.rb index e6bb8d1..ca439b8 100644 --- a/app/policies/contract_template_policy.rb +++ b/app/policies/contract_template_policy.rb @@ -3,8 +3,10 @@ class ContractTemplatePolicy < ApplicationPolicy def resolve if user.account_manager? 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 }) + else + scope.public_template.left_outer_joins(project: :project_memberships).where(project_memberships: { user_id: user.id }) end end end diff --git a/app/views/contract_templates/_form.html.erb b/app/views/contract_templates/_form.html.erb index ff40dfe..e2d164c 100644 --- a/app/views/contract_templates/_form.html.erb +++ b/app/views/contract_templates/_form.html.erb @@ -4,6 +4,10 @@ <%= 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.radio_button :accessibility, :public_template, label: "Public", wrapper_class: "mr-3" %> + <%= form.radio_button :accessibility, :private_template, label: "Private" %> +
<%= form.number_field :fee, min:"0", max:"99999999", step: "0.01", prepend: "$", wrapper_class: "col-sm-6" %>
diff --git a/config/locales/en.yml b/config/locales/en.yml index 4fd633d..290ef7e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -50,6 +50,7 @@ en: empty: Acquired Media Releases will appear here table_headers: file_infos_count: No. Files + name: Name notes: Notes signed_at: Date Signed tags: Tags @@ -151,6 +152,8 @@ en: empty: Appearance Releases will appear here imported_appearance_release_missing_attachment: Person photo or contract missing for imported appearance release table_headers: + contact_info: Contact info + name: Name notes: Notes signed_at: Date Signed tags: Tags @@ -742,6 +745,7 @@ en: empty: Location Releases will appear here table_headers: address: Address + name: Name notes: Notes signed_at: Date Signed tags: Tags @@ -776,6 +780,7 @@ en: search: Search empty: Material Releases will appear here table_headers: + name: Name notes: Notes signed_at: Date Signed tags: Tags @@ -798,6 +803,9 @@ en: empty: Medical releases will appear here table_headers: approved: Approved + approved?: Approved + contact_info: Contact info + name: Person name notes: Notes signed_at: Date Signed tags: Tags @@ -815,6 +823,8 @@ en: search: Search empty: Misc Releases will appear here table_headers: + contact_info: Contact info + name: Person name notes: Notes signed_at: Date Signed tags: Tags @@ -849,6 +859,7 @@ en: table_headers: composers_count: No. Composers file_infos_count: No. Files + name: Name notes: Notes publishers_count: No. Publishers signed_at: Date Signed @@ -1245,7 +1256,10 @@ en: search: Search empty: Talent Releases will appear here table_headers: + email: Email + name: Name notes: Notes + phone: Phone signed_at: Date Signed tags: Tags new: diff --git a/config/locales/es.yml b/config/locales/es.yml index 10d3be8..8c6711c 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,4 +1,14 @@ 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: attributes: appearance_release: @@ -41,6 +51,12 @@ es: heading: Person Photo (ES) index: 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: imported_appearance_release_contract_name: Contrato Importado imported_appearance_release_headshot_name: Retrato Importado @@ -296,21 +312,57 @@ es: form: photos: 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: form: photos: 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: custom_validation_errors: question_answer_is_required: answer is required (ES) index: table_headers: 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: actions: review: Review (ES) messages: 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: appearance_releases: create: @@ -415,6 +467,14 @@ es: heading: Second Guardian Photo (ES) guardian_photo: 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: 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) diff --git a/db/data_migrations/20200712192301_add_duration_to_broadcast_recordings.rb b/db/data_migrations/20200712192301_add_duration_to_broadcast_recordings.rb new file mode 100644 index 0000000..35efee1 --- /dev/null +++ b/db/data_migrations/20200712192301_add_duration_to_broadcast_recordings.rb @@ -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 \ No newline at end of file diff --git a/db/migrate/20200709120630_add_accessibility_to_contract_templates.rb b/db/migrate/20200709120630_add_accessibility_to_contract_templates.rb new file mode 100644 index 0000000..9ac3dd7 --- /dev/null +++ b/db/migrate/20200709120630_add_accessibility_to_contract_templates.rb @@ -0,0 +1,5 @@ +class AddAccessibilityToContractTemplates < ActiveRecord::Migration[6.0] + def change + add_column :contract_templates, :accessibility, :integer, default: 0 + end +end diff --git a/db/migrate/20200712181139_add_duration_to_broadcast_recordings.rb b/db/migrate/20200712181139_add_duration_to_broadcast_recordings.rb new file mode 100644 index 0000000..d79b21a --- /dev/null +++ b/db/migrate/20200712181139_add_duration_to_broadcast_recordings.rb @@ -0,0 +1,5 @@ +class AddDurationToBroadcastRecordings < ActiveRecord::Migration[6.0] + def change + add_column :broadcast_recordings, :duration, :float + end +end diff --git a/db/structure.sql b/db/structure.sql index 616c0ac..ba4ce52 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -9,6 +9,20 @@ 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: - -- @@ -494,7 +508,8 @@ CREATE TABLE public.broadcast_recordings ( asset_playback_uid character varying NOT NULL, file_name character varying 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_13_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'), ('20200625144713'), ('20200702152130'), -('20200707155717'); +('20200707155717'), +('20200709120630'), +('20200712181139'); diff --git a/spec/controllers/api/contract_templates_controller_spec.rb b/spec/controllers/api/contract_templates_controller_spec.rb index 6124c3b..161d67f 100644 --- a/spec/controllers/api/contract_templates_controller_spec.rb +++ b/spec/controllers/api/contract_templates_controller_spec.rb @@ -30,6 +30,21 @@ RSpec.describe Api::ContractTemplatesController, type: :controller do expect(response).to be_successful 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 private diff --git a/spec/controllers/api/sync_controller_spec.rb b/spec/controllers/api/sync_controller_spec.rb index 14b8de3..f34878a 100644 --- a/spec/controllers/api/sync_controller_spec.rb +++ b/spec/controllers/api/sync_controller_spec.rb @@ -127,9 +127,16 @@ RSpec.describe Api::SyncController, type: :controller do get :index medical_releases = attributes_for_type('medical_releases') - expect(medical_releases.first).to include('id') 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 private @@ -149,6 +156,13 @@ RSpec.describe Api::SyncController, type: :controller do create(:appearance_release, :minor_with_guardian_photo, project: project) 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 JSON.parse(response.body) end diff --git a/spec/factories/contract_templates.rb b/spec/factories/contract_templates.rb index 8d90846..22583c4 100644 --- a/spec/factories/contract_templates.rb +++ b/spec/factories/contract_templates.rb @@ -7,6 +7,7 @@ FactoryBot.define do body "This is a test contract template." guardian_clause "Is the signer a minor?" fee "$0.00" + accessibility "public_template" trait :archived do archived_at Time.zone.now diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 2f1b77a..1e9a73b 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -49,12 +49,18 @@ FactoryBot.define do predefined_client_name "nat_geo" end - factory :project_with_contract_template do + factory :project_with_contract_template_public do after(:build) do |project, _| project.contract_templates << build(:contract_template, project: nil) 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 after(:build) do |project, _| project.directories << build(:directory, project: nil, name: "Shared") diff --git a/spec/jobs/generate_contracts_zip_job_spec.rb b/spec/jobs/generate_contracts_zip_job_spec.rb index a438ae4..3d3ee5f 100644 --- a/spec/jobs/generate_contracts_zip_job_spec.rb +++ b/spec/jobs/generate_contracts_zip_job_spec.rb @@ -11,7 +11,7 @@ describe GenerateContractsZipJob do dir = Rails.root.join("spec", "fixtures", "files") files = ["contract.pdf", "AppearanceRelease.pdf"] # 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(:build).and_yield(dir, files) end @@ -35,6 +35,38 @@ describe GenerateContractsZipJob do expect(download.file).to be_attached 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 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_any_instance_of(ReleaseContractCollectionService).to receive(:build).and_raise(StandardError, "Contracts or contract templates not found") end - + it "updates status to 'failure' and sends user a notification" do GenerateContractsZipJob.perform_now(project, download, "AppearanceRelease", project.appearance_releases.ids) - + expect(download.status).to eq "failure" expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(download, I18n.t("contract_downloads.download.failure")) end @@ -56,6 +88,21 @@ describe GenerateContractsZipJob do # Delete the file created in fixture. # Or the tests will fail on next run due to already existing files in existing zip. 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 diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 4210321..5df8155 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -36,7 +36,7 @@ RSpec.describe Project, type: :model do describe "#import_contract_templates" 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) expect { diff --git a/spec/policies/contract_template_policy_spec.rb b/spec/policies/contract_template_policy_spec.rb index 241ca38..f1055f4 100644 --- a/spec/policies/contract_template_policy_spec.rb +++ b/spec/policies/contract_template_policy_spec.rb @@ -75,14 +75,17 @@ describe ContractTemplatePolicy do end permissions ".scope" do - let!(:member_project) do - create(:project_with_contract_template, name: "Member Project", members: user, account: account) + let!(:member_project_public_template) do + 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 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 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 let(:account) { build(:account) } @@ -93,7 +96,8 @@ describe ContractTemplatePolicy do context "for an account manager" do 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.not_to include(outside_project.contract_templates.first) } end @@ -101,15 +105,17 @@ describe ContractTemplatePolicy do context "for manager" do 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(outside_project.contract_templates.first) } end context "for associate" do 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(outside_project.contract_templates.first) } end