Compare commits

...

19 Commits

Author SHA1 Message Date
Senad Uka
6a2fb533cb Directmeba 2020-06-29 10:42:08 +02:00
Senad Uka
8951667e61 Upstrream sync 2020-06-26 18:45:11 +02:00
Senad Uka
fe131491cd Upstream sync 2020-06-26 04:55:50 +02:00
Senad Uka
290dbfa48b Upstream sync 2020-06-25 08:46:11 +02:00
Senad Uka
319cd89b29 Upstream sync 2020-06-24 04:48:12 +02:00
Senad Uka
6b0ea5b7df Upstream sync 2020-06-23 17:10:53 +02:00
Senad Uka
afee9d9bc9 Upstream sync 2020-06-22 20:28:22 +02:00
Senad Uka
072142811f Upstream sync 2020-06-22 14:14:25 +02:00
Senad Uka
b924b99762 Upstream sync 2020-06-19 09:23:07 +02:00
Senad Uka
988ef2beab Upstream sync 2020-06-18 17:51:08 +02:00
Senad Uka
1168bcdfdd Upstream sync 2020-06-18 16:56:11 +02:00
Senad Uka
a7b90c223b Upstream sync 2020-06-17 14:39:10 +02:00
Senad Uka
9a540efc74 Upstream sync 2020-06-16 17:11:04 +02:00
Senad Uka
028e946fcf Upstream sync 2020-06-15 08:33:23 +02:00
Senad Uka
fbf3173747 Upstream sync 2020-06-12 16:38:59 +02:00
Senad Uka
5f5e6c18b5 Upstream sync 2020-06-11 16:56:29 +02:00
Senad Uka
dc9ba08e1b Upstream sync 2020-06-10 11:19:35 +02:00
Senad Uka
cd5bbaeb62 Upstream sync master 2020-06-09 06:35:40 +02:00
Senad Uka
64bda6eab6 Upstream sync 2020-06-03 17:14:04 +02:00
173 changed files with 5430 additions and 573 deletions

View File

@@ -95,14 +95,28 @@ rake i18n:sort
``` ```
## Zoom.us integration ## Zoom.us integration
DirectMe app offers live broadcasting. Users are offered to paralelly connect to the Zoom meeting to have a video conference while the streaming happens. In order to use the Zoom functionality, the app needs to have the API keys provided. You need Zoom PRO account for this feature. DirectMe app offers live broadcasting feature. Users are offered to paralelly connect to the Zoom meeting to have a video conference while the streaming happens. In order to use the Zoom functionality, the app needs to have the API and verification token keys provided along with the account number that is available after login into the Zoom account. You need to have Zoom PRO subscription in order to use this feature.
#### Zoom.us api keys #### Zoom.us api keys
1. Log in to you zoom.us account 1. Log in to you zoom.us account
2. Go to https://marketplace.zoom.us/develop/create 2. Go to https://marketplace.zoom.us/develop/create
3. Choose JWT application 3. Choose JWT application
4. Copy API Key and API Secret 4. Copy API Key and API Secret
5. Set up ZOOM_API_KEY and ZOOM_API_SECRET environment variables
#### Setup
There is some configuration that has to be done through the API on the Zoom account so that you can use the feature. Run `rails zoom:setup` rake task to do it.
#### Zoom.us webhooks
To ensure integrity in between different Zoom environments, the app uses Zoom webhooks. To set them up, go to https://marketplace.czoom.us -> Develop -> JWT app -> Feature -> Event Subscriptions and enable following hooks:
* Start Meeting
* End Meeting
* All Recordings have completed
* User has been created
* User had been deleted
#### Syncing app with Zoom account configuration
If you are setting up the app to use Zoom account that has been previously used with DirectME, it is a good idea to make sure that the db state reflects the account situation. To do that, run `rails zoom:sync` rake task.
## Working Locally ## Working Locally

View File

@@ -1,23 +1,23 @@
$(document).on "turbolinks:load", -> $(document).on "turbolinks:load", ->
# Only connect if a broadcast-token meta tag is present subscribeToBroadcast = (broadcastToken) -> App.cable.subscriptions.create { channel: "BroadcastsChannel", token: broadcastToken },
broadcast_meta = document.querySelector("meta[name=broadcast-token]")
return unless broadcast_meta
broadcastToken = broadcast_meta.getAttribute("content")
App.public = App.cable.subscriptions.create { channel: "BroadcastsChannel", token: broadcastToken },
connected: -> connected: ->
# Called when the subscription is ready for use on the server # Called when the subscription is ready for use on the server
console.info "Subscribed to channel for broadcast:#{broadcastToken}"
disconnected: -> disconnected: ->
# Called when the subscription has been terminated by the server # Called when the subscription has been terminated by the server
received: (data) -> received: (data) ->
return unless document.querySelector("meta[name=broadcast-token][content='#{broadcastToken}']")
switch data.event switch data.event
when "broadcast_stream_update" then @refreshBroadcastVideo(data) when "broadcast_stream_update"
when "stream_recording_ready" then @showBroadcastRecordings(data) return unless document.querySelector("meta[name=broadcast-token][current=true][content='#{broadcastToken}']")
when "file_upload_update" then @refreshFilesTab(data) @refreshBroadcastVideo(data)
when "stream_recording_ready"
return unless document.querySelector("meta[name=broadcast-token][current=true][content='#{broadcastToken}']")
@showBroadcastRecordings(data)
when "file_upload_update"
return unless document.querySelector("meta[name=broadcast-token][content='#{broadcastToken}']")
@refreshBroadcastFilesTab(data)
refreshBroadcastVideo: (data) -> refreshBroadcastVideo: (data) ->
$("#broadcast_updates").html data.status_content $("#broadcast_updates").html data.status_content
@@ -38,8 +38,12 @@ $(document).on "turbolinks:load", ->
$(".flash-message").html data.flash_content $(".flash-message").html data.flash_content
$("#broadcast_recordings").html data.recordings_content $("#broadcast_recordings").html data.recordings_content
$("#broadcast_recordings_nav").html data.recordings_nav_content $("#broadcast_recordings_nav").html data.recordings_nav_content
refreshFilesTab: (data) -> refreshBroadcastFilesTab: (data) ->
$("#broadcast_file_list").html data.files_content $("#broadcast_file_list_#{data.broadcast_token}").html data.files_content
$("#broadcast_files_pagination").html data.pagination_content $("#broadcast_files_pagination_#{data.broadcast_token}").html data.pagination_content
# Create a channel subscription for every broadcast included in the meta tags
get_token = (meta) -> meta.getAttribute("content")
broadcast_tokens = (get_token broadcast_meta for broadcast_meta in document.querySelectorAll("meta[name=broadcast-token]"))
subscribeToBroadcast token for token in broadcast_tokens

View File

@@ -1,11 +1,16 @@
$(document).on("change", "[data-toggle=collapse-select]", function(event) { $(document).on("change", "[data-toggle=collapse-select]", function(event) {
const select = event.target; const select = event.target;
const target = select.dataset.target; const mappings = JSON.parse(select.dataset.targetShowValuesMapping);
const showValues = JSON.parse(select.dataset.showValues);
$.each(mappings, function( key, value ) {
if (showValues.indexOf(select.value) > -1) { if (value.indexOf(select.value) > -1) {
$(target).show("fast"); $(key).show("fast");
} else { } else {
$(target).hide("fast"); $(key).hide("fast");
} }
});
}); });
$(document).on("turbolinks:load", function() {
$("[data-toggle=collapse-select]").trigger("change");
});

View File

@@ -39,7 +39,7 @@ function selectBroadcast(clicked_element, checkbox) {
if (broadcast_ids.length >= 2) { if (broadcast_ids.length >= 2) {
multi_view_ids = $.param({multi_view_ids: broadcast_ids}); multi_view_ids = $.param({multi_view_ids: broadcast_ids});
broadcast_url = "/en/projects/" + project_id + "/broadcasts/" + broadcast_ids[0] + "?" + multi_view_ids broadcast_url = "/en/projects/" + project_id + "/broadcasts/" + broadcast_ids[0] + "?" + multi_view_ids
$("#multi_view_broadcasts").attr("href", broadcast_url); $("#multi_view_broadcasts").attr("href", broadcast_url);
$("#multi_view_broadcasts").attr("target", "_blank"); $("#multi_view_broadcasts").attr("target", "_blank");
$("#multi_view_broadcasts").removeClass('disabled'); $("#multi_view_broadcasts").removeClass('disabled');

View File

@@ -51,10 +51,8 @@ $(document).on("turbolinks:load", function() {
$("[data-behavior=guardian-photo-preview]").each(function(index, element) { $("[data-behavior=guardian-photo-preview]").each(function(index, element) {
App.PhotoPreview.init(element); App.PhotoPreview.init(element);
}); });
$("[data-behavior=take-person-photo]").click(function(e) { $("[data-behavior=trigger-click]").click(function(e) {
$("[data-ujs-target=person-photo-input]").trigger("click"); const target = $(this).data("target");
}); $(target).trigger("click");
$("[data-behavior=take-guardian-photo]").click(function(e) {
$("[data-ujs-target=guardian-photo-input]").trigger("click");
}); });
}); });

View File

@@ -6,6 +6,11 @@
@import "dropzone/dist/dropzone"; @import "dropzone/dist/dropzone";
@import 'bootstrap-datepicker'; @import 'bootstrap-datepicker';
// Global styles
label {
text-transform: capitalize;
}
// Wordmarks // Wordmarks
.suite-wordmark { .suite-wordmark {
font-weight: normal; font-weight: normal;

View File

@@ -31,7 +31,7 @@ u {
} }
.page { .page {
page-break-before: always; page-break-before: always;
} }
.logo { .logo {
@@ -44,6 +44,14 @@ u {
text-align: right; text-align: right;
} }
.qr-code {
margin-right: -30px;
}
.do-not-copy-warning {
padding-right: 15px;
}
.heading-table td { .heading-table td {
width: 50%; width: 50%;
} }

View File

@@ -35,11 +35,12 @@ class BroadcastsChannel < ApplicationCable::Channel
recordings_nav_content: recordings_nav_content recordings_nav_content: recordings_nav_content
end end
def self.file_upload_updates(broadcast, files, pagination_content) def self.broadcast_file_upload_updates(broadcast, files, pagination_content)
files_content = ApplicationController.render partial: "broadcasts/file", collection: files files_content = ApplicationController.render partial: "broadcasts/file", collection: files
broadcast_to broadcast, { broadcast_to broadcast, {
event: :file_upload_update, event: :file_upload_update,
broadcast_token: broadcast.token,
files_content: files_content, files_content: files_content,
pagination_content: pagination_content pagination_content: pagination_content
} }

View File

@@ -61,7 +61,8 @@ class AcquiredMediaReleasesController < ApplicationController
:name, :name,
:territory, :territory,
:term, :term,
:person_name, :person_first_name,
:person_last_name,
:person_phone, :person_phone,
:person_email, :person_email,
:person_company, :person_company,

View File

@@ -24,8 +24,12 @@ class Api::BroadcastsController < Api::ApiController
def update def update
file_params.each do |file| file_params.each do |file|
file[:io] = StringIO.new(Base64.decode64(file[:io])) if file.is_a?(String)
@broadcast.files.attach(io: file[:io], filename: file[:filename]) @broadcast.files.attach(file)
else
file[:io] = StringIO.new(Base64.decode64(file[:io]))
@broadcast.files.attach(file.to_h.symbolize_keys)
end
end end
@broadcast.save! @broadcast.save!

View File

@@ -0,0 +1,50 @@
# Duplicated from ActiveStorage::DirectUploadsController
# https://github.com/rails/rails/blob/v6.0.0/activestorage/app/controllers/active_storage/direct_uploads_controller.rb
class Api::DirectUploadsController < Api::ApiController
include ActiveStorage::SetCurrent
deserializable_resource :direct_upload, only: [:create]
def create
blob = ActiveStorage::Blob.create_before_direct_upload!(blob_params)
render jsonapi: DirectUpload.new(blob)
end
private
def blob_params
params.
require(:direct_upload).
permit(:type, :filename, :byte_size, :checksum, :content_type, :metadata).
except(:type).
to_h.symbolize_keys
end
class DeserializableDirectUpload < JSONAPI::Deserializable::Resource
attributes :filename, :byte_size, :checksum, :content_type, :metadata
end
class SerializableDirectUpload < JSONAPI::Serializable::Resource
type 'direct_upload'
attributes :id, :key, :signed_id, :url, :headers
end
class DirectUpload
delegate :id, :key, :signed_id, to: :blob
attr_reader :blob
def initialize(blob)
@blob = blob
end
def url
blob.service_url_for_direct_upload
end
def headers
blob.service_headers_for_direct_upload
end
end
end

View File

@@ -3,7 +3,6 @@
class AppearanceReleaseImportsController < ApplicationController class AppearanceReleaseImportsController < ApplicationController
include AppearanceReleaseContext include AppearanceReleaseContext
include ProjectContext include ProjectContext
include CreateReleasableJobs
before_action :set_project, only: [:create] before_action :set_project, only: [:create]
@@ -11,24 +10,16 @@ class AppearanceReleaseImportsController < ApplicationController
def create def create
authorize AppearanceRelease authorize AppearanceRelease
@failed_files = []
attachments = appearance_release_params attachments = appearance_release_params
if attachments.nil? if attachments.nil?
alert_message = t 'appearance_releases.create.no_attachments' alert_message = t 'appearance_releases.create.no_attachments'
redirect_to [@project, :appearance_releases], alert: alert_message
else else
attachments.each do |attachment| MatchAppearanceReleasesJob.perform_later(@project, attachments)
create_imported_appearance_release attachment notice_message = t 'appearance_releases.create.matching_started'
end redirect_to [@project, :appearance_releases], notice: notice_message
end end
unless @failed_files.empty?
alert_message = t 'appearance_releases.create.failed_import'
alert_message += '<br><ul>'
@failed_files.each { |file_name| alert_message += "<li>#{file_name}</li>" }
alert_message += '</ul>'
end
redirect_to [@project, :appearance_releases], alert: alert_message
end end
private private
@@ -45,45 +36,7 @@ class AppearanceReleaseImportsController < ApplicationController
params.require(:attachments) params.require(:attachments)
end end
def build_appearance_release(params = {}) def acceptable_extensions
authorize appearance_releases.build(params) AppearanceRelease.acceptable_import_file_extensions
end
def log_create_analytics
TrackAnalyticsJob.perform_later(Current.user, Current.account, :track_create_non_native_release, release_type: AppearanceRelease.to_s, user_agent: request.user_agent, user_ip: request.remote_ip)
end
def create_imported_appearance_release(attachment)
blob = ActiveStorage::Blob.find_signed(attachment)
return if blob.nil?
extension = blob.filename.extension_with_delimiter
unless AppearanceRelease.acceptable_import_file_extensions.include? extension
blob.purge
@failed_files << blob.filename
return
end
random_contract_no = AppearanceRelease.random_contract_number.to_s
appearance_release_params = {
person_last_name: random_contract_no
}
if blob.image?
appearance_release_params[:person_photo] = attachment
appearance_release_params[:person_first_name] = I18n.t('appearance_releases.shared.imported_appearance_release_headshot_name')
elsif extension == '.pdf'
appearance_release_params[:contract] = attachment
appearance_release_params[:person_first_name] = I18n.t('appearance_releases.shared.imported_appearance_release_contract_name')
end
appearance_release = build_appearance_release(appearance_release_params)
if appearance_release.save(context: :non_native)
log_create_analytics
after_create appearance_release
else
@failed_files << blob.filename
end
end end
end end

View File

@@ -77,9 +77,43 @@ class AppearanceReleasesController < ApplicationController
results results
end end
def person_params
%i[
person_first_name
person_last_name
person_phone
person_email
person_photo
person_address_street1
]
end
def guardian_params
%i[
guardian_first_name
guardian_last_name
guardian_phone
guardian_email
guardian_photo
guardian_address_street1
]
end
def second_guardian_params
%i[
guardian_2_first_name
guardian_2_last_name
guardian_2_phone
guardian_2_email
guardian_2_photo
guardian_2_address_street1
]
end
def appearance_release_params def appearance_release_params
params.require(:appearance_release).permit(:contract, :guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_photo, :minor, params.require(:appearance_release).permit(person_params,
:person_address, :person_first_name, :person_last_name, :person_phone, :person_email, :person_photo, guardian_params, second_guardian_params,
:contract, :minor,
:applicable_medium_id, :applicable_medium_text, :applicable_medium_id, :applicable_medium_text,
:territory_id, :territory_text, :territory_id, :territory_text,
:term_id, :term_text, :person_date_of_birth, :term_id, :term_text, :person_date_of_birth,

View File

@@ -1,6 +1,6 @@
class BroadcastsController < ApplicationController class BroadcastsController < ApplicationController
layout "project" layout "project"
before_action :set_project before_action :set_project
before_action :build_broadcast, only: [:new, :create] before_action :build_broadcast, only: [:new, :create]
before_action :set_broadcast, only: [:show, :destroy, :update] before_action :set_broadcast, only: [:show, :destroy, :update]
@@ -24,19 +24,19 @@ class BroadcastsController < ApplicationController
end end
end end
def show
@conference_url = url_for [@broadcast.project, @broadcast, :zoom_meeting]
@recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page])
@files = @broadcast.files.order("created_at DESC").paginate(page: params[:files_page])
render layout: 'application'
end
def update def update
@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)
pagination_content = ApplicationController.render html: helpers.will_paginate(@files, params: { active_tab: params[:active_tab] }) 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.file_upload_updates(@broadcast, @files, pagination_content) BroadcastsChannel.broadcast_file_upload_updates(@broadcast, @files, pagination_content)
end
def show
@conference_url = url_for [@broadcast.project, @broadcast, :zoom_meeting]
@recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page])
@files = @broadcast.files.order("created_at DESC").paginate(page: params[:page])
render layout: 'application'
end end
def destroy def destroy
@@ -71,7 +71,10 @@ class BroadcastsController < ApplicationController
def set_multi_view_broadcasts def set_multi_view_broadcasts
authorized_broadcasts = authorize policy_scope(Broadcast).where(id: params[:multi_view_ids]).order_by_recent authorized_broadcasts = authorize policy_scope(Broadcast).where(id: params[:multi_view_ids]).order_by_recent
@multi_view_broadcasts = authorized_broadcasts.map { |b| MultiViewBroadcast.new(b, params[:multi_view_ids]) } @multi_view_broadcasts = authorized_broadcasts.map do |b|
files_page = params[:files_page] if params[:active_files_tab] == b.token
MultiViewBroadcast.new(b, params[:multi_view_ids], files_page)
end
end end
def filtered_broadcasts def filtered_broadcasts
@@ -90,20 +93,29 @@ class BroadcastsController < ApplicationController
class MultiViewBroadcast class MultiViewBroadcast
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
delegate_missing_to :@broadcast delegate_missing_to :@broadcast
def initialize(broadcast, multi_view_ids) def initialize(broadcast, multi_view_ids, paginate_page)
@broadcast = broadcast @broadcast = broadcast
@multi_view_ids = multi_view_ids @multi_view_ids = multi_view_ids
@paginate_page = paginate_page
end end
def url def url
project_broadcast_path(@broadcast.project, @broadcast, multi_view_ids: @multi_view_ids, locale: I18n.locale) project_broadcast_path(@broadcast.project, @broadcast, multi_view_ids: @multi_view_ids, locale: I18n.locale)
end end
def files
@broadcast.files.order("created_at DESC").paginate(page: @paginate_page)
end
def uid def uid
id id
end end
def self.model_name
Broadcast.model_name
end
end end
end end

View File

@@ -0,0 +1,13 @@
module MedicalReleaseContext
extend ActiveSupport::Concern
def medical_releases
policy_scope(MedicalRelease)
end
def set_medical_release
medical_release_id = params[:medical_release_id] || params[:id]
@medical_release = authorize medical_releases.find(medical_release_id)
end
end

View File

@@ -0,0 +1,13 @@
module MiscReleaseContext
extend ActiveSupport::Concern
def misc_releases
policy_scope(MiscRelease)
end
def set_misc_release
misc_release_id = params[:misc_release_id] || params[:id]
@misc_release = authorize misc_releases.find(misc_release_id)
end
end

View File

@@ -61,7 +61,15 @@ class ContractTemplatesController < ApplicationController
: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,
:restriction_id, :restriction_text) :restriction_id, :restriction_text,
:question_1_text, :question_2_text,
:question_3_text, :question_4_text,
:question_5_text, :question_6_text,
:question_7_text, :question_8_text,
:question_9_text, :question_10_text,
:question_11_text, :question_12_text,
:question_13_text, :question_14_text,
:question_15_text)
end end
def download_attributes def download_attributes

View File

@@ -48,8 +48,10 @@ class ContractsController < ApplicationController
# Native release contracts must be generated on-the-fly; non-native releases have a contract attachment # Native release contracts must be generated on-the-fly; non-native releases have a contract attachment
if releasable.native? if releasable.native?
send_file contract.to_pdf, download_attributes send_file contract.to_pdf, download_attributes
else elsif policy(contract).show?
redirect_to releasable.contract.service_url redirect_to releasable.contract.service_url
else
raise Pundit::NotAuthorizedError
end end
end end
end end

View File

@@ -68,7 +68,8 @@ class LocationReleasesController < ApplicationController
:territory_id, :territory_text, :territory_id, :territory_text,
:term_id, :term_text, :term_id, :term_text,
:restriction_id, :restriction_text, :restriction_id, :restriction_text,
:filming_started_on, :filming_ended_on :filming_started_on, :filming_ended_on,
:filming_hours
) )
end end

View File

@@ -0,0 +1,40 @@
class MedicalReleasesController < ApplicationController
include ProjectContext, MedicalReleaseContext
before_action :set_project, only: [:index]
before_action :set_medical_release, only: [:destroy]
include ProjectLayout
def index
@medical_releases = filtered_medical_releases.order_by_recent.paginate(page: params[:page])
end
def destroy
@project = @medical_release.project
if @medical_release.destroy
redirect_to [@project, :medical_releases], alert: t(".alert")
end
end
private
def medical_releases
if @project
policy_scope(@project.medical_releases)
else
policy_scope(MedicalRelease)
end
end
def filtered_medical_releases
results = medical_releases
if params[:query].present?
results = results.search(params[:query])
end
results
end
end

View File

@@ -0,0 +1,40 @@
class MiscReleasesController < ApplicationController
include ProjectContext, MiscReleaseContext
before_action :set_project, only: [:index]
before_action :set_misc_release, only: [:destroy]
include ProjectLayout
def index
@misc_releases = filtered_misc_releases.order_by_recent.paginate(page: params[:page])
end
def destroy
@project = @misc_release.project
if @misc_release.destroy
redirect_to [@project, :misc_releases], alert: t(".alert")
end
end
private
def misc_releases
if @project
policy_scope(@project.misc_releases)
else
policy_scope(MiscRelease)
end
end
def filtered_misc_releases
results = misc_releases
if params[:query].present?
results = results.search(params[:query])
end
results
end
end

View File

@@ -60,7 +60,7 @@ class ProjectsController < ApplicationController
end end
def features_settings_params def features_settings_params
%i(appearance_release location_release material_release acquired_media_release music_release talent_release video_analysis) %i(appearance_release location_release material_release acquired_media_release music_release talent_release medical_release misc_release video_analysis)
end end
def project_params_with_current_account def project_params_with_current_account

View File

@@ -45,6 +45,9 @@ class Public::AcquiredMediaReleasesController < Public::BaseController
params.require(:acquired_media_release).permit( params.require(:acquired_media_release).permit(
:name, :name,
:description, :description,
:person_first_name,
:person_last_name,
:person_email,
:person_title, :person_title,
:person_phone, :person_phone,
:person_fax, :person_fax,

View File

@@ -39,11 +39,60 @@ class Public::AppearanceReleasesController < Public::BaseController
authorize appearance_releases.build(params) authorize appearance_releases.build(params)
end end
def person_params
%i[
person_first_name
person_last_name
person_phone
person_email
person_photo
person_address_street1
person_address_street2
person_address_city
person_address_state
person_address_zip
person_address_country
]
end
def guardian_params
%i[
guardian_first_name
guardian_last_name
guardian_phone
guardian_email
guardian_photo
guardian_address_street1
guardian_address_street2
guardian_address_city
guardian_address_state
guardian_address_zip
guardian_address_country
]
end
def second_guardian_params
%i[
guardian_2_first_name
guardian_2_last_name
guardian_2_phone
guardian_2_email
guardian_2_photo
guardian_2_address_street1
guardian_2_address_street2
guardian_2_address_city
guardian_2_address_state
guardian_2_address_zip
guardian_2_address_country
]
end
def appearance_release_params def appearance_release_params
params.require(:appearance_release).permit(:person_address, :person_first_name, :person_last_name, :person_phone, :person_email, :person_photo, params.require(:appearance_release).permit(person_params, guardian_params,
:guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_photo, :minor, second_guardian_params,
:signature_base64, :person_date_of_birth, :minor, :signature_base64,
:locale, :contract_template,) :person_date_of_birth,
:locale, :contract_template)
end end
def appearance_release_params_with_locale def appearance_release_params_with_locale

View File

@@ -6,8 +6,8 @@ class Public::BroadcastsController < Public::BaseController
@conference_url = broadcast_zoom_meeting_url(@broadcast.token) @conference_url = broadcast_zoom_meeting_url(@broadcast.token)
@multi_view_broadcasts = multi_view_broadcasts @multi_view_broadcasts = multi_view_broadcasts
@recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page]) @recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page])
@files = @broadcast.files.order("created_at DESC").paginate(page: params[:page]) @files = @broadcast.files.order("created_at DESC").paginate(page: params[:files_page])
render 'broadcasts/show' render 'broadcasts/show'
end end
@@ -15,8 +15,8 @@ class Public::BroadcastsController < Public::BaseController
@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)
pagination_content = ApplicationController.render html: helpers.will_paginate(@files, params: { active_tab: params[:active_tab] }) 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.file_upload_updates(@broadcast, @files, pagination_content) BroadcastsChannel.broadcast_file_upload_updates(@broadcast, @files, pagination_content)
end end
private private
@@ -29,29 +29,45 @@ class Public::BroadcastsController < Public::BaseController
Broadcast. Broadcast.
where(token: params[:multi_view_tokens]). where(token: params[:multi_view_tokens]).
order_by_recent. order_by_recent.
map { |b| MultiViewBroadcast.new(b, params[:multi_view_tokens]) } map do |b|
files_page = params[:files_page] if params[:active_files_tab] == b.token
MultiViewBroadcast.new(b, params[:multi_view_tokens], files_page)
end
end end
def set_broadcast def set_broadcast
@broadcast = Broadcast.find_by_token(params[:token]) @broadcast = Broadcast.find_by_token(params[:token])
unless @broadcast.present?
redirect_to [:new, :session], alert: t(".alert")
end
end end
class MultiViewBroadcast class MultiViewBroadcast
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
delegate_missing_to :@broadcast delegate_missing_to :@broadcast
def initialize(broadcast, multi_view_tokens) def initialize(broadcast, multi_view_tokens, paginate_page)
@broadcast = broadcast @broadcast = broadcast
@multi_view_tokens = multi_view_tokens @multi_view_tokens = multi_view_tokens
@paginate_page = paginate_page
end end
def url def url
broadcast_url(uid, multi_view_tokens: @multi_view_tokens, host: AppHost.new.domain_with_port, locale: I18n.locale) broadcast_url(uid, multi_view_tokens: @multi_view_tokens, host: AppHost.new.domain_with_port, locale: I18n.locale)
end end
def files
@broadcast.files.order("created_at DESC").paginate(page: @paginate_page)
end
def uid def uid
token token
end end
def self.model_name
Broadcast.model_name
end
end end
end end

View File

@@ -63,7 +63,9 @@ class Public::LocationReleasesController < Public::BaseController
:person_address_zip, :person_address_zip,
:person_address_country, :person_address_country,
:signature_base64, :signature_base64,
:locale, :contract_template, :filming_started_on, :filming_ended_on :locale, :contract_template, :filming_started_on, :filming_ended_on,
:filming_hours,
photos: []
) )
end end

View File

@@ -45,7 +45,7 @@ class Public::MaterialReleasesController < Public::BaseController
:person_first_name, :person_last_name, :person_title, :person_company, :person_phone, :person_email, :person_first_name, :person_last_name, :person_title, :person_company, :person_phone, :person_email,
: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,
:signature_base64, :signature_base64,
:locale, :contract_template, :description :locale, :contract_template, :description, photos: []
) )
end end

View File

@@ -0,0 +1,123 @@
class Public::MedicalReleasesController < Public::BaseController
before_action :set_account, :set_project, :set_contract_template
def new
@medical_release = build_medical_release
end
def create
@medical_release = build_medical_release(medical_release_params_with_locale_and_contract_template)
if @medical_release.save(context: :native)
if @medical_release.contract_template.present?
AttachContractToReleasableJob.perform_later(@medical_release)
end
log_create_analytics
else
render :new
end
end
private
def set_project
@project = @account.projects.find(params[:project_id])
end
def set_account
@account = Account.find_by(slug: params[:account_id])
end
def set_contract_template
@contract_template = @project.contract_templates.find(params[:contract_template_id])
end
def medical_releases
policy_scope(@project.medical_releases)
end
def build_medical_release(params = {})
authorize medical_releases.build(params)
end
def medical_release_params
params
.require(:medical_release)
.permit(
person_params,
guardian_params,
second_guardian_params,
:minor,
:signature_base64,
:locale,
:contract_template,
:question_1_answer, :question_2_answer,
:question_3_answer, :question_4_answer,
:question_5_answer, :question_6_answer,
:question_7_answer, :question_8_answer,
:question_9_answer, :question_10_answer,
:question_11_answer, :question_12_answer,
:question_13_answer, :question_14_answer,
:question_15_answer, photos: [],
)
end
def person_params
%i[
person_first_name
person_last_name
person_phone
person_email
person_address_street1
person_address_street2
person_address_city
person_address_state
person_address_zip
person_address_country
]
end
def guardian_params
%i[
guardian_first_name
guardian_last_name
guardian_phone
guardian_email
guardian_photo
guardian_address_street1
guardian_address_street2
guardian_address_city
guardian_address_state
guardian_address_zip
guardian_address_country
]
end
def second_guardian_params
%i[
guardian_2_first_name
guardian_2_last_name
guardian_2_phone
guardian_2_email
guardian_2_photo
guardian_2_address_street1
guardian_2_address_street2
guardian_2_address_city
guardian_2_address_state
guardian_2_address_zip
guardian_2_address_country
]
end
def medical_release_params_with_locale
medical_release_params.merge(locale: I18n.locale)
end
def medical_release_params_with_locale_and_contract_template
medical_release_params_with_locale.merge(contract_template: @contract_template)
end
def log_create_analytics
TrackAnalyticsJob.perform_later(nil, nil, :track_create_native_release, release_type: MedicalRelease.to_s, account: @account, user_agent: request.user_agent, user_ip: request.remote_ip)
end
end

View File

@@ -0,0 +1,99 @@
class Public::MiscReleasesController < Public::BaseController
before_action :set_account, :set_project, :set_contract_template
def new
@misc_release = build_misc_release
end
def create
@misc_release = build_misc_release(misc_release_params_with_locale_and_contract_template)
if @misc_release.save(context: :native)
if @misc_release.contract_template.present?
AttachContractToReleasableJob.perform_later(@misc_release)
end
log_create_analytics
else
render :new
end
end
private
def set_project
@project = @account.projects.find(params[:project_id])
end
def set_account
@account = Account.find_by(slug: params[:account_id])
end
def set_contract_template
@contract_template = @project.contract_templates.find(params[:contract_template_id])
end
def misc_releases
policy_scope(@project.misc_releases)
end
def build_misc_release(params = {})
authorize misc_releases.build(params)
end
def misc_release_params
params
.require(:misc_release)
.permit(
person_params,
guardian_params,
:signature_base64,
:locale,
:contract_template,
photos: [],
)
end
def person_params
[
:person_first_name,
:person_last_name,
:person_phone,
:person_email,
:person_address_street1,
:person_address_street2,
:person_address_city,
:person_address_state,
:person_address_zip,
:person_address_country,
]
end
def guardian_params
[
:guardian_first_name,
:guardian_last_name,
:guardian_phone,
:guardian_email,
:minor,
:guardian_address_street1,
:guardian_address_street2,
:guardian_address_city,
:guardian_address_state,
:guardian_address_zip,
:guardian_address_country,
:guardian_photo
]
end
def misc_release_params_with_locale
misc_release_params.merge(locale: I18n.locale)
end
def misc_release_params_with_locale_and_contract_template
misc_release_params_with_locale.merge(contract_template: @contract_template)
end
def log_create_analytics
TrackAnalyticsJob.perform_later(nil, nil, :track_create_native_release, release_type: MiscRelease.to_s, account: @account, user_agent: request.user_agent, user_ip: request.remote_ip)
end
end

View File

@@ -11,7 +11,9 @@ class ReleaseTemplateImportsController < ApplicationController
templates = [] templates = []
filtered_contract_templates.each do |contract_template| filtered_contract_templates.each do |contract_template|
next if contract_template.duplicated? || contract_template.project == @project next if contract_template.duplicated? ||
contract_template.archived? ||
contract_template.project == @project
already_imported = contract_template.duplicates.non_archived.pluck(:project_id).include?(@project.id) already_imported = contract_template.duplicates.non_archived.pluck(:project_id).include?(@project.id)
templates << OpenStruct.new(template: contract_template, already_imported?: already_imported) templates << OpenStruct.new(template: contract_template, already_imported?: already_imported)

View File

@@ -5,7 +5,7 @@ class ZoomNotificationsController < ApplicationController
skip_before_action :verify_authenticity_token skip_before_action :verify_authenticity_token
before_action :authorize_zoom before_action :authorize_zoom
before_action :set_zoom_meeting, only: :create before_action :set_zoom_meeting, only: [:create], if: :meeting_event?
def create def create
case notification_event case notification_event
@@ -16,6 +16,12 @@ class ZoomNotificationsController < ApplicationController
when 'recording.completed' when 'recording.completed'
recording = notification.dig(:payload, :object, :recording_files).first recording = notification.dig(:payload, :object, :recording_files).first
AttachRecordingToZoomMeetingJob.perform_later(@zoom_meeting, recording, notification['download_token']) AttachRecordingToZoomMeetingJob.perform_later(@zoom_meeting, recording, notification['download_token'])
when 'user.deleted'
zoom_user = ZoomUser.find_by(api_id: notification.dig(:payload, :object, :id))
if zoom_user.present?
zoom_user.api_id = nil
zoom_user.destroy
end
else else
Rails.logger.info notification_event Rails.logger.info notification_event
Rails.logger.info notification Rails.logger.info notification
@@ -42,6 +48,10 @@ class ZoomNotificationsController < ApplicationController
notification.dig(:payload, :object, :host_id) notification.dig(:payload, :object, :host_id)
end end
def meeting_event?
notification_event.split(".").first.to_s.in? %w(meeting recording)
end
def set_zoom_meeting def set_zoom_meeting
@zoom_meeting = ZoomMeeting.find_by!(api_meeting_id: notification_meeting_id) @zoom_meeting = ZoomMeeting.find_by!(api_meeting_id: notification_meeting_id)
end end

View File

@@ -2,9 +2,13 @@ module DropzoneHelper
def dropzone_placeholder_message_for(releasable) def dropzone_placeholder_message_for(releasable)
case releasable.model_name.param_key case releasable.model_name.param_key
when "acquired_media_release" when "acquired_media_release"
"To Add Photos & Videos to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse photos and connect to Camera" '(Optional) To add the licensed photos or videos ("Property") to this release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse photos and connect to Camera'
when "material_release"
t 'material_releases.form.photos.dropzone_label'
when "music_release" when "music_release"
"To Add Audio Files to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files" "To Add Audio Files to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files"
when "location_release"
t 'location_releases.form.photos.dropzone_label'
when "directory" when "directory"
"To Add Files to the Folder:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files" "To Add Files to the Folder:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files"
else else

View File

@@ -1,4 +1,3 @@
require 'zoom_gateway'
class AttachRecordingToZoomMeetingJob < ApplicationJob class AttachRecordingToZoomMeetingJob < ApplicationJob
queue_as :default queue_as :default

View File

@@ -0,0 +1,100 @@
# frozen_string_literal: true
class MatchAppearanceReleasesJob < ApplicationJob
queue_as :default
def perform(project, attachments)
filtered_attachments_object = filter_attachments attachments
return if filtered_attachments_object[:keys].blank?
matching_request = MatchingRequest.create project: project, attachments: filtered_attachments_object[:signed_ids]
payload = { request_id: matching_request.id, bucket: aws_bucket_name, files: filtered_attachments_object[:keys]}
response = BrayniacAI::QrMatching.create! payload
matches = response.matches || []
key_signed_id_hash = Hash[filtered_attachments_object[:keys].zip(filtered_attachments_object[:signed_ids])]
handle_matches matches, project, key_signed_id_hash
matching_request.destroy
end
private
def handle_matches(matches, project, key_signed_id_hash)
matches.each do |match|
contract_key = Array.wrap(match.contracts).first
headshot_key = Array.wrap(match.headshots).first
identifier = match.identifier
contract = key_signed_id_hash[contract_key]
headshot = key_signed_id_hash[headshot_key]
next if contract.nil? && headshot.nil?
identified_release = identifier.blank? ? nil : AppearanceRelease.find_by(identifier: identifier)
if identified_release.nil?
create_release project, contract, headshot, identifier
else
update_release identified_release, contract, headshot
end
end
end
def create_release(project, contract, headshot, identifier)
random_contract_no = AppearanceRelease.random_contract_number.to_s
is_incomplete = contract.nil? || headshot.nil?
params = {
project: project,
person_first_name: appearance_first_name(is_incomplete),
person_last_name: random_contract_no
}
params[:person_photo] = headshot unless headshot.nil?
params[:contract] = contract unless contract.nil?
params[:identifier] = identifier unless blank?
return if AppearanceRelease.create(params)
logger.error "Failed to create AppearanceRelease with params : \r\n#{params}"
end
def update_release(release, contract, headshot)
release.contract = contract unless contract.nil?
release.person_photo = headshot unless headshot.nil?
release.save
end
def appearance_first_name(incomplete)
if incomplete
I18n.t('appearance_releases.shared.incomplete_match')
else
I18n.t('appearance_releases.shared.matched_import')
end
end
def aws_bucket_name
ENV.fetch 'AWS_BUCKET'
end
def filter_attachments(attachments)
filtered_attachments_keys = []
filtered_attachments_signed_ids = []
attachments.each do |attachment|
blob = ActiveStorage::Blob.find_signed attachment
next if blob.nil?
extension = blob.filename.extension
next unless blob.image? || extension == 'pdf'
filtered_attachments_keys << blob.key
filtered_attachments_signed_ids << attachment
end
{
keys: filtered_attachments_keys,
signed_ids: filtered_attachments_signed_ids
}
end
end

View File

@@ -55,6 +55,9 @@ class Account < ApplicationRecord
User.joins(:project_memberships).where(project_memberships: { project: projects }), User.joins(:project_memberships).where(project_memberships: { project: projects }),
Broadcast.where(project: projects), Broadcast.where(project: projects),
ZoomMeeting.where(project: projects), ZoomMeeting.where(project: projects),
MedicalRelease.where(project: projects),
MiscRelease.where(project: projects),
MatchingRequest.where(project: projects),
self self
])).sum(:byte_size).to_f ])).sum(:byte_size).to_f
end end

View File

@@ -43,7 +43,8 @@ class AcquiredMediaRelease < ApplicationRecord
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
] ]
CATEGORIES = ["Artwork", "Film Footage", "Video Footage", "Still Photograph"].freeze # CATEGORIES = ["Artwork", "Film Footage", "Video Footage", "Still Photograph"].freeze
CATEGORIES = ["Film Footage", "Video Footage", "Still Photograph"].freeze
def minor? def minor?
false false

View File

@@ -12,10 +12,46 @@ class AppearanceRelease < ApplicationRecord
include Taggable include Taggable
include PersonName include PersonName
include GuardianPhotoable include GuardianPhotoable
include SecondGuardianPhotoable
include GuardianName include GuardianName
include SecondGuardianName
has_one_attached :person_photo has_one_attached :person_photo
composed_of :person_address,
class_name: 'Address',
mapping: [
%w[person_address_street1 street1],
%w[person_address_street2 street2],
%w[person_address_city city],
%w[person_address_state state],
%w[person_address_zip zip],
%w[person_address_country country]
]
composed_of :guardian_address,
class_name: 'Address',
mapping: [
%w[guardian_address_street1 street1],
%w[guardian_address_street2 street2],
%w[guardian_address_city city],
%w[guardian_address_state state],
%w[guardian_address_zip zip],
%w[guardian_address_country country]
]
composed_of :guardian_2_address,
class_name: 'Address',
mapping: [
%w[guardian_2_address_street1 street1],
%w[guardian_2_address_street2 street2],
%w[guardian_2_address_city city],
%w[guardian_2_address_state state],
%w[guardian_2_address_zip zip],
%w[guardian_2_address_country country]
]
# These validations apply to all releases # These validations apply to all releases
validates :person_email, email: true, allow_blank: true validates :person_email, email: true, allow_blank: true
validates :person_first_name, :person_last_name, presence: true validates :person_first_name, :person_last_name, presence: true
@@ -39,6 +75,7 @@ class AppearanceRelease < ApplicationRecord
# These validations apply to releases being signed by a minor # These validations apply to releases being signed by a minor
with_options if: :minor? do with_options if: :minor? do
validates :guardian_first_name, :guardian_last_name, presence: true validates :guardian_first_name, :guardian_last_name, presence: true
validates :guardian_email, email: true, allow_blank: true
end end
validates :person_photo, content_type: face_photo_acceptable_content_types validates :person_photo, content_type: face_photo_acceptable_content_types
@@ -70,7 +107,18 @@ class AppearanceRelease < ApplicationRecord
scope :having_no_person_photo, -> { left_joins(:person_photo_attachment).group(:id).having('COUNT(active_storage_attachments) = 0') } scope :having_no_person_photo, -> { left_joins(:person_photo_attachment).group(:id).having('COUNT(active_storage_attachments) = 0') }
scope :with_person_name, ->(name) { where('person_first_name ILIKE ? OR person_last_name ILIKE ?', "%#{name}%") } scope :with_person_name, ->(name) { where('person_first_name ILIKE ? OR person_last_name ILIKE ?', "%#{name}%") }
searchable_on %i[person_first_name person_last_name person_address person_email person_phone] searchable_on %i[
person_first_name
person_last_name
person_address_street1
person_address_street2
person_address_city
person_address_state
person_address_zip
person_address_country
person_email
person_phone
]
# All releases must respond to the following messages # All releases must respond to the following messages
def name def name
@@ -97,6 +145,10 @@ class AppearanceRelease < ApplicationRecord
true true
end end
def second_guardian_present?
self.guardian_2_first_name.present?
end
def contract_file_name def contract_file_name
"#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime('%Y.%m.%d')}_#{release_number}_#{filename_suffix.parameterize}" "#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime('%Y.%m.%d')}_#{release_number}_#{filename_suffix.parameterize}"
end end

View File

@@ -8,7 +8,7 @@ class BlankContract
end end
def to_pdf def to_pdf
kit = PDFKit.new(as_html) kit = PDFKit.new(as_html, margin_right: 1, margin_left: 1, margin_top: 10, margin_bottom: 1)
kit.to_file("tmp/#{filename}") kit.to_file("tmp/#{filename}")
end end

View File

@@ -0,0 +1,9 @@
# frozen_string_literal: true
module Attachable
extend ActiveSupport::Concern
included do
has_many_attached :attachments
end
end

View File

@@ -0,0 +1,20 @@
module SecondGuardianName
extend ActiveSupport::Concern
included do
def guardian_2_name
"#{guardian_2_first_name} #{guardian_2_last_name}".titleize
end
def guardian_2_name=(value)
if value.include?(' ')
split = value.split(" ", 2)
self.guardian_2_first_name = split.first
self.guardian_2_last_name = split.last
else
self.guardian_2_first_name = value
self.guardian_2_last_name = "(Not Given)"
end
end
end
end

View File

@@ -0,0 +1,9 @@
module SecondGuardianPhotoable
extend ActiveSupport::Concern
included do
has_one_attached :guardian_2_photo
validates :guardian_2_photo, content_type: ["image/png", "image/jpeg"]
end
end

View File

@@ -29,6 +29,10 @@ class Contract
} }
end end
def medical_release?
@releasable.instance_of?(MedicalRelease)
end
private private
def contract_template def contract_template

View File

@@ -13,6 +13,8 @@ class ContractTemplate < ApplicationRecord
has_many :acquired_media_releases, dependent: :restrict_with_error has_many :acquired_media_releases, dependent: :restrict_with_error
has_many :location_releases, dependent: :restrict_with_error has_many :location_releases, dependent: :restrict_with_error
has_many :material_releases, dependent: :restrict_with_error has_many :material_releases, dependent: :restrict_with_error
has_many :medical_releases, dependent: :restrict_with_error
has_many :misc_releases, dependent: :restrict_with_error
monetize :fee_cents monetize :fee_cents
has_rich_text :body has_rich_text :body
@@ -50,6 +52,10 @@ class ContractTemplate < ApplicationRecord
parent.present? parent.present?
end end
def archived?
archived_at.present?
end
def archive def archive
update(archived_at: Time.zone.now) update(archived_at: Time.zone.now)
end end

View File

@@ -23,7 +23,7 @@ class HeadshotCollection
collection_uid: collection_uid.to_s, collection_uid: collection_uid.to_s,
bucket_name: aws_bucket_name, bucket_name: aws_bucket_name,
ids_to_images: map_ids_to_images, ids_to_images: map_ids_to_images,
}.reject { |_, v| v.blank? } }.reject { |k, v| v.blank? && k != :ids_to_images }
end end
private private

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
class MatchingRequest < ApplicationRecord
include Attachable
belongs_to :project
end

View File

@@ -0,0 +1,79 @@
class MedicalRelease < ApplicationRecord
include Contractable
include Notable
include Photoable
include Releasable
include Searchable
include Signable
include Syncable
include PersonName
include GuardianPhotoable
include SecondGuardianPhotoable
include GuardianName
include SecondGuardianName
NUMBER_OF_CUSTOM_FIELDS = 15
composed_of :person_address,
class_name: "Address",
mapping: [
%w(person_address_street1 street1),
%w(person_address_street2 street2),
%w(person_address_city city),
%w(person_address_state state),
%w(person_address_zip zip),
%w(person_address_country country)
]
def self.face_photo_acceptable_content_types
["image/png", "image/jpeg"]
end
# These validations apply to all releases
validates :person_first_name, :person_last_name, presence: true
validates :person_email, email: true, allow_blank: true
acts_as_taggable_on :internal_tags, :tags
# These validations apply to releases being signed by a minor
with_options if: :minor? do
validates :guardian_email, email: true, allow_blank: true
validates :guardian_2_email, email: true, allow_blank: true
end
# These validations apply to releases created natively by the system (i.e. not imported from elsewhere)
with_options on: :native do
validates :signature, attached: true
end
# These validations apply to releases imported to the system from an outside source
with_options on: :non_native do
validates :contract, attached: true
end
searchable_on %i[
person_first_name person_last_name person_email person_phone
person_address_street1 person_address_street2 person_address_city person_address_state person_address_zip person_address_country
]
# All releases must respond to the following messages
def name
person_name
end
def filename_suffix
"#{person_last_name} #{person_first_name}"
end
def contact_person
@contact_person ||= Contact.new(person_name, person_address, person_email, person_phone)
end
def uses_edl?
false
end
def contract_file_name
"#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime("%Y.%m.%d")}_#{release_number}_#{filename_suffix.parameterize}"
end
end

View File

@@ -0,0 +1,86 @@
class MiscRelease < ApplicationRecord
include Contractable
include Notable
include Photoable
include Releasable
include Searchable
include Signable
include Syncable
include PersonName
include GuardianName
include GuardianPhotoable
composed_of :person_address,
class_name: "Address",
mapping: [
%w(person_address_street1 street1),
%w(person_address_street2 street2),
%w(person_address_city city),
%w(person_address_state state),
%w(person_address_zip zip),
%w(person_address_country country)
]
composed_of :guardian_address,
class_name: "Address",
mapping: [
%w(guardian_address_street1 street1),
%w(guardian_address_street2 street2),
%w(guardian_address_city city),
%w(guardian_address_state state),
%w(guardian_address_zip zip),
%w(guardian_address_country country)
]
def self.face_photo_acceptable_content_types
["image/png", "image/jpeg"]
end
# These validations apply to all releases
validates :person_first_name, :person_last_name, presence: true
validates :person_email, email: true, allow_blank: true
acts_as_taggable_on :internal_tags, :tags
# These validations apply to releases created natively by the system (i.e. not imported from elsewhere)
with_options on: :native do
validates :signature, attached: true
end
# These validations apply to releases imported to the system from an outside source
with_options on: :non_native do
validates :contract, attached: true
end
with_options if: :minor? do
validates :guardian_first_name, :guardian_last_name, presence: true
validates :guardian_phone, presence: true
end
searchable_on %i[
person_first_name person_last_name person_email person_phone
person_address_street1 person_address_street2 person_address_city person_address_state person_address_zip person_address_country
guardian_address_street1 guardian_address_street2 guardian_address_city guardian_address_state guardian_address_zip guardian_address_country
]
# All releases must respond to the following messages
def name
person_name
end
def filename_suffix
"#{person_last_name} #{person_first_name}"
end
def contact_person
@contact_person ||= Contact.new(person_name, person_address, person_email, person_phone)
end
def uses_edl?
false
end
def contract_file_name
"#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime("%Y.%m.%d")}_#{release_number}_#{filename_suffix.parameterize}"
end
end

View File

@@ -3,8 +3,8 @@ class Project < ApplicationRecord
include Filterable include Filterable
include Syncable include Syncable
SIGNABLE_RELEASE_TYPES = %w(talent appearance acquired_media location material) SIGNABLE_RELEASE_TYPES = %w(talent appearance acquired_media location material medical misc)
AVAILABLE_RELEASE_TYPES = %w(appearance location material acquired_media talent music) AVAILABLE_RELEASE_TYPES = %w(appearance location material acquired_media talent music medical misc)
belongs_to :account belongs_to :account
has_many :acquired_media_releases, dependent: :destroy has_many :acquired_media_releases, dependent: :destroy
@@ -13,6 +13,8 @@ class Project < ApplicationRecord
has_many :material_releases, dependent: :destroy has_many :material_releases, dependent: :destroy
has_many :music_releases, dependent: :destroy has_many :music_releases, dependent: :destroy
has_many :talent_releases, dependent: :destroy has_many :talent_releases, dependent: :destroy
has_many :medical_releases, dependent: :destroy
has_many :misc_releases, dependent: :destroy
has_many :videos, dependent: :destroy has_many :videos, dependent: :destroy
has_many :imports, dependent: :destroy has_many :imports, dependent: :destroy
has_many :contract_templates, dependent: :destroy has_many :contract_templates, dependent: :destroy
@@ -33,6 +35,8 @@ class Project < ApplicationRecord
material_release: false, material_release: false,
music_release: false, music_release: false,
talent_release: false, talent_release: false,
medical_release: false,
misc_release: false,
video_analysis: false, video_analysis: false,
} }
end end
@@ -65,6 +69,8 @@ class Project < ApplicationRecord
material_release: true, material_release: true,
music_release: true, music_release: true,
talent_release: true, talent_release: true,
medical_release: true,
misc_release: true,
video_analysis: true, video_analysis: true,
} }
when "nat_geo" when "nat_geo"
@@ -76,6 +82,8 @@ class Project < ApplicationRecord
material_release: true, material_release: true,
music_release: true, music_release: true,
talent_release: true, talent_release: true,
medical_release: true,
misc_release: true,
video_analysis: true, video_analysis: true,
} }
else else
@@ -117,7 +125,7 @@ class Project < ApplicationRecord
current_zoom_meeting = zoom_meetings.active.first current_zoom_meeting = zoom_meetings.active.first
unless current_zoom_meeting.present? unless current_zoom_meeting.present?
zoom_user = ZoomUser.free.first || ZoomUser.create zoom_user = ZoomUser.for_new_meeting
current_zoom_meeting = ZoomMeeting.create(zoom_user: zoom_user, project: self) current_zoom_meeting = ZoomMeeting.create(zoom_user: zoom_user, project: self)
end end

View File

@@ -24,7 +24,7 @@ class QrCode
end end
end end
def to_base64_png(width = 100, height = 100) def to_base64_png(width = 200, height = 200)
_qr_code.as_png.resize(width, height).to_data_url _qr_code.as_png.resize(width, height).to_data_url
end end

View File

@@ -1,5 +1,5 @@
class ReleasableParam class ReleasableParam
TYPES = %w(talent appearance location material acquired_media music) TYPES = %w(talent appearance location material acquired_media music medical misc)
def initialize(params) def initialize(params)
@params = params @params = params

View File

@@ -8,7 +8,12 @@ class SampleAppearanceRelease < AppearanceRelease
def default_attrs def default_attrs
{ {
person_address: "Street Address, City, State Zipcode", person_address_street1: "Street Address",
person_address_street2: "St2",
person_address_city: "City",
person_address_state: "State",
person_address_zip: "ZIP",
person_address_country: "Country",
person_first_name: "Some", person_first_name: "Some",
person_last_name: "Person", person_last_name: "Person",
person_phone: "555-555-5555", person_phone: "555-555-5555",

View File

@@ -1,5 +1,3 @@
require 'zoom_gateway'
class ZoomMeeting < ApplicationRecord class ZoomMeeting < ApplicationRecord
belongs_to :project, optional: true belongs_to :project, optional: true
belongs_to :zoom_user belongs_to :zoom_user

View File

@@ -1,19 +1,27 @@
require 'zoom_gateway' require 'securerandom'
class ZoomUser < ApplicationRecord class ZoomUser < ApplicationRecord
has_many :zoom_meetings, dependent: :nullify has_many :zoom_meetings, dependent: :nullify
enum tier: [:basic, :pro]
after_create :create_api_user, if: -> { api_id.nil? } after_create :create_api_user, if: -> { api_id.nil? }
before_destroy :abort_destroy before_destroy :abort_destroy
scope :current_account, -> { where(account_number: ZoomGateway.ACCOUNT_NUMBER) }
scope :free, -> { where.not(id: ZoomMeeting.active.pluck(:zoom_user_id)) } scope :free, -> { where.not(id: ZoomMeeting.active.pluck(:zoom_user_id)) }
def api_email
self.class.api_email(self.id)
end
def create_api_user def create_api_user
self.api_id = gateway.create_host(api_email) retries ||= 0
self.api_id = gateway.create_host(self.class.generate_api_email)
self.account_number = ZoomGateway.ACCOUNT_NUMBER
save save
rescue ZoomGateway::UserAlreadyExists => e
retries += 1
if retries < 3
retry # new api email will be generated automatically
else
raise e
end
end end
def delete_api_user def delete_api_user
@@ -22,9 +30,22 @@ class ZoomUser < ApplicationRecord
save save
end end
def current_account?
account_number == ZoomGateway.ACCOUNT_NUMBER
end
# Static methods
class << self class << self
def api_email(id) def generate_api_email
"host#{id}@directme" "host#{SecureRandom.random_number(10000)}@directme"
end
def for_new_meeting
user = public_send(ZoomGateway.USER_TYPE_NAME).current_account.free.first
if user.nil?
user = public_send(ZoomGateway.USER_TYPE_NAME).current_account.create
end
user
end end
end end

View File

@@ -1,5 +1,9 @@
class ContractPolicy < ApplicationPolicy class ContractPolicy < ApplicationPolicy
def show? def show?
user.manager? || user.account_manager? if record.respond_to?(:medical_release?) && record.medical_release?
user.account_manager?
else
user.manager? || user.account_manager?
end
end end
end end

View File

@@ -0,0 +1,41 @@
class MedicalReleasePolicy < ReleasePolicy
def create?
true
end
def show?
true
end
def update?
!record.native?
end
def destroy?
true
end
def edit_photos?
true
end
def index?
true
end
def update_photos?
edit_photos?
end
def tag_multiple?
true
end
def download_single?
user.account_manager?
end
def download_multiple?
download_single?
end
end

View File

@@ -0,0 +1,41 @@
class MiscReleasePolicy < ReleasePolicy
def create?
true
end
def show?
true
end
def update?
!record.native?
end
def destroy?
true
end
def edit_photos?
true
end
def index?
true
end
def update_photos?
edit_photos?
end
def tag_multiple?
true
end
def download_single?
true
end
def download_multiple?
download_single?
end
end

View File

@@ -4,7 +4,7 @@
<div class="form-row"> <div class="form-row">
<%= form.text_field :name, required: true, wrapper_class: "col-12" %> <%= form.text_field :name, required: true, wrapper_class: "col-12" %>
</div> </div>
<%= form.form_group :categories, label: { text: "Categories" } do %> <%= form.form_group :categories, label: { text: "Licensed property type" } do %>
<% AcquiredMediaRelease::CATEGORIES.each do |category| %> <% AcquiredMediaRelease::CATEGORIES.each do |category| %>
<%= form.check_box :categories, { multiple: true, label: category }, category, false %> <%= form.check_box :categories, { multiple: true, label: category }, category, false %>
<% end %> <% end %>

View File

@@ -13,18 +13,29 @@
<div class="form-row"> <div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %> <%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
<%= form.date_field :person_date_of_birth, wrapper_class: "col-sm-6", placeholder: Date.current %> <%= form.date_field :person_date_of_birth, wrapper_class: "col-sm-6", placeholder: Date.current %>
<%= form.text_field :person_address, wrapper_class: "col-sm-6" %> <%= form.text_field :person_address_street1, wrapper_class: "col-sm-6" %>
</div> </div>
<div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields"> <div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields">
<div class="form-row"> <%= card_field_set_tag t(".guardian_info.heading") do %>
<%= form.text_field :guardian_first_name, required: appearance_release.minor?, wrapper_class: "col-sm-3" %> <div class="form-row">
<%= form.text_field :guardian_last_name, required: appearance_release.minor?, wrapper_class: "col-sm-3" %> <%= form.text_field :guardian_first_name, required: appearance_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %> <%= form.text_field :guardian_last_name, required: appearance_release.minor?, wrapper_class: "col-sm-3" %>
</div> <%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %>
<div class="form-row"> <%= form.text_field :guardian_email, wrapper_class: "col-sm-6" %>
<%= form.text_field :guardian_address, wrapper_class: "col-sm-6" %> <%= form.text_field :guardian_address_street1, wrapper_class: "col-sm-6" %>
</div> </div>
<% end %>
<%= card_field_set_tag t(".guardian_2_info.heading") do %>
<div class="form-row">
<%= form.text_field :guardian_2_first_name, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_2_last_name, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_2_phone, wrapper_class: "col-sm-6" %>
<%= form.text_field :guardian_2_email, wrapper_class: "col-sm-6" %>
<%= form.text_field :guardian_2_address_street1, wrapper_class: "col-sm-6" %>
</div>
<% end %>
</div> </div>
<% end %> <% end %>
@@ -59,20 +70,36 @@
<div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields"> <div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields">
<div class="text-left"> <div class="text-left">
<p><%= t(".photos.guardian_photo.heading") %></p> <p><%= t(".photos.guardian_photo.heading") %></p>
<div class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-photo-input]"> <div id='guardian-photo-preview' class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-photo-input]">
<div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center"> <div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center">
<span>No photo yet</span> <span>No photo yet</span>
</div> </div>
</div> </div>
<% if appearance_release.guardian_photo.attached? %> <% if appearance_release.guardian_photo.attached? %>
<%= javascript_tag nonce: true do %> <%= javascript_tag nonce: true do %>
App.PhotoPreview.set("[data-behavior=guardian-photo-preview]", "<%= url_for(appearance_release.guardian_photo.variant(auto_orient: true, resize: '200x200')) %>"); App.PhotoPreview.set("#guardian-photo-preview", "<%= url_for(appearance_release.guardian_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %> <% end %>
<% end %> <% end %>
<div class="d-inline-block"> <div class="d-inline-block">
<%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if appearance_release.guardian_photo.attached?%> <%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if appearance_release.guardian_photo.attached?%>
<%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, help: "PNG or JPG only", accept: appearance_release.class.face_photo_acceptable_content_types.join(",") %> <%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, help: "PNG or JPG only", accept: appearance_release.class.face_photo_acceptable_content_types.join(",") %>
</div> </div>
<p><%= t(".photos.guardian_2_photo.heading") %></p>
<div id='guardian-2-photo-preview' class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-2-photo-input]">
<div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center">
<span>No photo yet</span>
</div>
</div>
<% if appearance_release.guardian_2_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("#guardian-2-photo-preview", "<%= url_for(appearance_release.guardian_2_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %>
<% end %>
<div class="d-inline-block">
<%= form.hidden_field :guardian_2_photo, value: form.object.guardian_2_photo.signed_id if appearance_release.guardian_2_photo.attached?%>
<%= form.file_field :guardian_2_photo, hide_label: true, data: { ujs_target: "guardian-2-photo-input" }, help: "PNG or JPG only", accept: appearance_release.class.face_photo_acceptable_content_types.join(",") %>
</div>
</div> </div>
</div> </div>
<% end %> <% end %>

View File

@@ -2,6 +2,10 @@
<div class="page"> <div class="page">
<% has_logo = local_assigns[:logo] %> <% has_logo = local_assigns[:logo] %>
<table class="heading-table"> <table class="heading-table">
<tr>
<td>&nbsp;</td>
<td class="do-not-copy-warning"><strong><%= t '.do_not_copy_warning' %></strong></td>
</tr>
<tr> <tr>
<td> <td>
<% if has_logo %> <% if has_logo %>
@@ -11,17 +15,9 @@
<% end %> <% end %>
</td> </td>
<td> <td>
<img src="<%= qr_codes[copy_index] %>" /> <img class="qr-code" src="<%= qr_codes[copy_index] %>" />
</td> </td>
</tr> </tr>
<tr>
<td>&nbsp;</td>
<td class="serial-number"><%= serial_numbers[copy_index] %></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><strong><%= t '.do_not_copy_warning' %></strong></td>
</tr>
</table> </table>
<hr> <hr>
<% if contract_template.body.present? %> <% if contract_template.body.present? %>

View File

@@ -1,4 +1,4 @@
<%= bootstrap_form_for model, layout: :inline, remote: true do |form| %> <%= bootstrap_form_for model, layout: :inline, remote: true do |form| %>
<%= form.file_field :files, direct_upload: true, multiple: true, accept: "*", hide_label: true, wrapper_class: "w-65 mr-2" %> <%= form.file_field :files, direct_upload: true, multiple: true, accept: "*", hide_label: true, required: true, wrapper_class: "w-65 mr-2", id: "broadcast_files_#{token}" %>
<%= form.button fa_icon("upload", text: "Add File"), class: "btn btn-primary", type: :submit, data: { disable_with: fa_icon("spinner", text: "Adding File") } %> <%= form.button fa_icon("upload", text: "Add File"), class: "btn btn-primary", type: :submit, data: { disable_with: fa_icon("spinner", text: "Adding File") } %>
<% end %> <% end %>

View File

@@ -0,0 +1,21 @@
<div class="text-center pb-2" id="broadcast_file_form_<%= broadcast.token %>">
<% if controller.class.module_parent.to_s == "Public" %>
<%= render partial: "public/broadcasts/file_form", locals: { model: [broadcast], token: broadcast.token } %>
<% else %>
<%= render partial: "broadcasts/file_form", locals: { model: [broadcast.project, broadcast], token: broadcast.token } %>
<% end %>
</div>
<div class="overflow-auto mh-30">
<ul class="list-unstyled d-flex flex-column align-items-center text-center" id="broadcast_file_list_<%= broadcast.token %>">
<% if files.present? %>
<%= render partial: "broadcasts/file", collection: files %>
<% else %>
<li class="my-3">
Files will appear here.
</li>
<% end %>
</ul>
<div class="d-flex mt-2 justify-content-center" id="broadcast_files_pagination_<%= broadcast.token %>">
<%= will_paginate(files, param_name: 'files_page', params: { active_files_tab: broadcast.token }) if files.present? %>
</div>
</div>

View File

@@ -3,7 +3,13 @@
<meta name="project-id" content="<%= @project.id %>"> <meta name="project-id" content="<%= @project.id %>">
<% end %> <% end %>
<% if @broadcast %> <% if @broadcast %>
<meta name="broadcast-token" content="<%= @broadcast.token %>"> <meta name="broadcast-token" current="true" content="<%= @broadcast.token %>">
<% end %>
<% # Subscribe to Action Cable for every broadcast including those in multi-view %>
<% @multi_view_broadcasts.each do |multi_view_broadcast| %>
<% if multi_view_broadcast.token != @broadcast.token %>
<meta name="broadcast-token" current="false" content="<%= multi_view_broadcast.token %>">
<% end %>
<% end %> <% end %>
<% end %> <% end %>
@@ -24,12 +30,10 @@
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<h1 class="h3 m-0"><%= @broadcast.name %></h1> <h1 class="h3 m-0"><%= @broadcast.name %></h1>
<div class="dropdown"> <div class="dropdown">
<a class="btn btn-light border dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <%= link_to "Switch View", "#", class: "btn btn-light border dropdown-toggle", role: "button", id: "dropdownMenuLink", data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } %>
Switch View
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink"> <div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<h5 class="dropdown-header">Live Streams</h5> <h5 class="dropdown-header">Live Streams</h5>
<span class="dropdown-item active"><%= fa_icon("check", text: @broadcast.name.titleize) %></span> <%= link_to fa_icon("check", text: @broadcast.name.titleize), "#", class: "dropdown-item active" %>
<% @multi_view_broadcasts.each do |broadcast| %> <% @multi_view_broadcasts.each do |broadcast| %>
<% if broadcast.id != @broadcast.id %> <% if broadcast.id != @broadcast.id %>
<%= link_to broadcast.name.titleize, broadcast.url, class: class_string("dropdown-item", "active" => @broadcast.id == broadcast.id) %> <%= link_to broadcast.name.titleize, broadcast.url, class: class_string("dropdown-item", "active" => @broadcast.id == broadcast.id) %>
@@ -72,13 +76,10 @@
<div class="card-header"> <div class="card-header">
<ul class="nav nav-tabs card-header-tabs"> <ul class="nav nav-tabs card-header-tabs">
<li class="nav-item"> <li class="nav-item">
<a class="<%= class_string("nav-link", "active" => !params[:active_tab].present?) %>" href="#home" data-toggle="tab">Home</a> <%= link_to "Home", "#home", class: class_string("nav-link", "active" => !params[:active_tab].present?), data: { toggle: "tab" } %>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="<%= class_string("nav-link", "active" => params[:active_tab] == "files") %>" href="#files" data-toggle="tab">Files</a> <%= link_to "Previous Sessions", "#recordings", class: class_string("nav-link", "active" => params[:active_tab] == "recordings"), data: { toggle: "tab" } %>
</li>
<li class="nav-item">
<a class="<%= class_string("nav-link", "active" => params[:active_tab] == "recordings") %>" href="#recordings" data-toggle="tab">Previous Sessions</a>
</li> </li>
</ul> </ul>
</div> </div>
@@ -118,29 +119,6 @@
<p class="card-text">If you want to join the ZOOM meeting dedicated to this broadcast, follow the link below.</p> <p class="card-text">If you want to join the ZOOM meeting dedicated to this broadcast, follow the link below.</p>
<%= link_to 'Video Conference', @conference_url, class: 'btn btn-primary btn-block', target: '_blank' %> <%= link_to 'Video Conference', @conference_url, class: 'btn btn-primary btn-block', target: '_blank' %>
</div> </div>
<div class="<%= class_string("tab-pane fade show", "active" => params[:active_tab] == 'files') %>" id="files">
<div class="text-center pb-2" id="broadcast_file_form">
<% if controller.class.module_parent.to_s == "Public" %>
<%= render partial: "public/broadcasts/file_form", locals: { model: [@broadcast], token: @broadcast.token } %>
<% else %>
<%= render partial: "broadcasts/file_form", locals: { model: [@project, @broadcast] } %>
<% end %>
</div>
<div class="overflow-auto mh-30">
<ul class="list-unstyled d-flex flex-column align-items-center text-center" id="broadcast_file_list">
<% if @files.present? %>
<%= render partial: "broadcasts/file", collection: @files %>
<% else %>
<li class="my-3">
Files will appear here.
</li>
<% end %>
</ul>
<div class="d-flex mt-2 justify-content-center" id="broadcast_files_pagination">
<%= will_paginate(@files, params: { active_tab: 'files' }) if @files.present? %>
</div>
</div>
</div>
<div class="<%= class_string("tab-pane fade show", "active" => params[:active_tab] == 'recordings') %>" id="recordings"> <div class="<%= class_string("tab-pane fade show", "active" => params[:active_tab] == 'recordings') %>" id="recordings">
<div id="broadcast_recordings"> <div id="broadcast_recordings">
<%= render partial: 'broadcasts/broadcast_recordings', locals: { recordings: @recordings, broadcast: @broadcast } %> <%= render partial: 'broadcasts/broadcast_recordings', locals: { recordings: @recordings, broadcast: @broadcast } %>
@@ -149,5 +127,36 @@
</div> </div>
</div> </div>
</div> </div>
<!-- files section -->
<div id="files" class="card shadow-sm mb-3">
<div class="card-header">
<h2 class="h5">Files</h2>
<% if @multi_view_broadcasts %>
<ul class="nav nav-tabs card-header-tabs">
<% @multi_view_broadcasts.each_with_index do |mvb, index| %>
<li class="nav-item">
<%= link_to mvb.name, "#files_broadcast_#{mvb.token}", class: class_string("nav-link", "active" => (params[:active_files_tab] == mvb.token || (params[:active_files_tab].nil? && index == 0))), data: { toggle: "tab" } %>
</li>
<% end %>
</ul>
<% end %>
</div>
<div class="card-body p-3">
<div class="tab-content">
<% if @multi_view_broadcasts.present? %>
<% @multi_view_broadcasts.each_with_index do |mvb, index| %>
<div class="<%= class_string("tab-pane fade show", "active" => (params[:active_files_tab] == mvb.token || (params[:active_files_tab].nil? && index == 0))) %>" id="files_broadcast_<%= mvb.token %>">
<%= render partial: 'broadcasts/files_section', locals: { broadcast: mvb, files: mvb.files } %>
</div>
<% end %>
<% else %>
<div class="tab-pane fade show active" id="files_broadcast_<%= @broadcast.id %>">
<%= render partial: 'broadcasts/files_section', locals: { broadcast: @broadcast, files: @files } %>
</div>
<% end %>
</div>
</div>
</div>
</div> </div>
<div> </div>

View File

@@ -1,9 +1,9 @@
$("#broadcast_file_form").html("<%= j render(partial: "broadcasts/file_form", locals: { model: [@project, @broadcast] }) %>"); $("#broadcast_file_form_<%= @broadcast.token %>").html("<%= j render(partial: "broadcasts/file_form", locals: { model: [@project, @broadcast], token: @broadcast.token }) %>");
var file_id = "#<%= dom_id(@files.first) %>" var file_id = "#<%= dom_id(@files.first) %>"
if ($("#broadcast_file_list").has(file_id).length == 0) { if ($("#broadcast_file_list_<%= @broadcast.token %>").has(file_id).length == 0) {
$("#broadcast_file_list").html("<%= j render(partial: "broadcasts/file", collection: @files) %>"); $("#broadcast_file_list_<%= @broadcast.token %>").html("<%= j render(partial: "broadcasts/file", collection: @files) %>");
$("#broadcast_files_pagination").html("<%= j will_paginate(@files) %>"); $("#broadcast_files_pagination_<%= @broadcast.token %>").html("<%= j will_paginate(@files, param_name: 'files_page', params: { active_files_tab: @broadcast.token }) %>");
} }
bsCustomFileInput.init(); bsCustomFileInput.init();

View File

@@ -2,21 +2,20 @@
<%= field_set_tag content_tag(:span, t(".release_info.heading"), class: "h6 text-muted text-uppercase") do %> <%= field_set_tag content_tag(:span, t(".release_info.heading"), class: "h6 text-muted text-uppercase") do %>
<div class="form-row"> <div class="form-row">
<%= 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: "#guardian_clause", show_values: %w(appearance talent) }, 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) } }, class: "form-control custom-select" %>
</div> </div>
<div class="form-row"> <div class="form-row" id="fee_field">
<%= form.number_field :fee, min:"0", max:"99999999", step: "0.01", prepend: "$", help: "Leave at $0.00 for no-fee", wrapper_class: "col-sm-6" %> <%= form.number_field :fee, min:"0", max:"99999999", step: "0.01", prepend: "$", wrapper_class: "col-sm-6" %>
</div> </div>
<% end %> <% end %>
<hr> <hr>
<%= field_set_tag content_tag(:span, t(".exploitable_rights.heading"), class: "h6 text-muted text-uppercase")do %> <%= field_set_tag content_tag(:span, t(".exploitable_rights.heading"), class: "h6 text-muted text-uppercase"), id: "exploitable_rights_fields" do %>
<%= render "shared/exploitable_rights_fields", form: form %> <%= render "shared/exploitable_rights_fields", form: form %>
<hr>
<% end %> <% end %>
<hr>
<%= field_set_tag content_tag(:span, t(".legal.heading"), class: "h6 text-muted text-uppercase") do %> <%= field_set_tag content_tag(:span, t(".legal.heading"), class: "h6 text-muted text-uppercase") do %>
<%= form.form_group do %> <%= form.form_group do %>
<%= form.rich_text_area :body %> <%= form.rich_text_area :body %>
@@ -28,6 +27,12 @@
</div> </div>
<% end %> <% end %>
<%= field_set_tag content_tag(:span, t(".custom_fields.heading"), class: "h6 text-muted text-uppercase"), id: "custom_fields", style: "display: none;" do %>
<p class="alert alert-info"><%= fa_icon("info-circle", text: t(".custom_fields.instructions")) %></p>
<%= render "shared/custom_fields", form: form %>
<hr>
<% end %>
<div class="row align-items-center text-center mt-4"> <div class="row align-items-center text-center mt-4">
<%= link_to t("shared.cancel"), [project, :contract_templates], class: "col-3 text-reset" %> <%= link_to t("shared.cancel"), [project, :contract_templates], class: "col-3 text-reset" %>
<div class="col-3"> <div class="col-3">

View File

@@ -0,0 +1,8 @@
<p class="heading"><strong><u><%= t ".heading" %></u></strong></p>
<% (1..MedicalRelease::NUMBER_OF_CUSTOM_FIELDS).each do |n| %>
<% if contract_template.public_send("question_#{n}_text").present? %>
<p><strong><%= contract_template.public_send("question_#{n}_text") %></strong></p>
<p><%= releasable.public_send("question_#{n}_answer") %></p>
<% end %>
<% end %>

View File

@@ -5,6 +5,9 @@
<% if release.respond_to? :guardian_photo %> <% if release.respond_to? :guardian_photo %>
<% @total_photos_count += release.guardian_photo.attached? ? 1 : 0 %> <% @total_photos_count += release.guardian_photo.attached? ? 1 : 0 %>
<% end %> <% end %>
<% if release.respond_to? :guardian_2_photo %>
<% @total_photos_count += release.guardian_2_photo.attached? ? 1 : 0 %>
<% end %>
<p class="heading"><strong><u><%= t '.heading', count: @total_photos_count %></u></strong></p> <p class="heading"><strong><u><%= t '.heading', count: @total_photos_count %></u></strong></p>
<ul> <ul>
@@ -29,6 +32,14 @@
<%= release.guardian_photo.filename.to_s %> <%= release.guardian_photo.filename.to_s %>
</li> </li>
<% end %> <% end %>
<% if release.respond_to?(:guardian_2_photo) && release.guardian_2_photo.attached? %>
<br>
<p class="heading"><strong><%= t '.guardian_2_photo_heading' %></strong></p>
<li>
<%= image_tag release.guardian_2_photo.variant(auto_orient: true, resize: "200x200") %><br />
<%= release.guardian_2_photo.filename.to_s %>
</li>
<% end %>
<% end %> <% end %>
</ul> </ul>

View File

@@ -29,6 +29,7 @@
<% if releasable.model_name == "LocationRelease" %> <% if releasable.model_name == "LocationRelease" %>
<%= description_list_pair "Filming Started On:", releasable&.filming_started_on&.strftime("%D") %> <%= description_list_pair "Filming Started On:", releasable&.filming_started_on&.strftime("%D") %>
<%= description_list_pair "Filming Ended On:", releasable&.filming_ended_on&.strftime("%D") %> <%= description_list_pair "Filming Ended On:", releasable&.filming_ended_on&.strftime("%D") %>
<%= description_list_pair "Filming Hours:", releasable&.filming_hours %>
<% end %> <% end %>
<% if contract_template.fee? %> <% if contract_template.fee? %>
<%= description_list_pair "Fee:", number_to_currency(contract_template.fee) %> <%= description_list_pair "Fee:", number_to_currency(contract_template.fee) %>
@@ -55,7 +56,23 @@
<%= description_list_pair_for releasable, :guardian_name, append: ":" %> <%= description_list_pair_for releasable, :guardian_name, append: ":" %>
<%= description_list_pair_for releasable, :guardian_address, append: ":" %> <%= description_list_pair_for releasable, :guardian_address, append: ":" %>
<%= description_list_pair_for releasable, :guardian_phone, append: ":" %> <%= description_list_pair_for releasable, :guardian_phone, append: ":" %>
<%= description_list_pair_for releasable, :guardian_email, append: ":" %>
<%= description_list_pair_for releasable, :signed_on, append: ":" %> <%= description_list_pair_for releasable, :signed_on, append: ":" %>
</dl> </dl>
<% if releasable.respond_to?(:second_guardian_present?) && releasable.second_guardian_present? %>
<br/>
<p class="text-left"><strong>Second guardian Information</strong></p>
<% # Second guardian information %>
<dl>
<%= description_list_pair_for releasable, :guardian_2_name, append: ":" %>
<%= description_list_pair_for releasable, :guardian_2_address, append: ":" %>
<%= description_list_pair_for releasable, :guardian_2_phone, append: ":" %>
<%= description_list_pair_for releasable, :guardian_2_email, append: ":" %>
</dl>
<% end %>
<% end %> <% end %>

View File

@@ -15,6 +15,13 @@
<p class="text-left"><strong>Guardian Clause</strong></p> <p class="text-left"><strong>Guardian Clause</strong></p>
<%= contract_template.guardian_clause %> <%= contract_template.guardian_clause %>
<% end %> <% end %>
<% if releasable.model_name == "MedicalRelease" %>
<div class="page">
<%= render "contracts/medical_questionnaire", releasable: releasable, contract_template: contract_template, preview: preview %>
</div>
<% end %>
<div class="page"> <div class="page">
<%= render "contracts/signature_page", releasable: releasable, contract_template: contract_template, preview: preview %> <%= render "contracts/signature_page", releasable: releasable, contract_template: contract_template, preview: preview %>
</div> </div>

View File

@@ -11,14 +11,10 @@
<%= field_set_tag content_tag(:span, t(".signer_details.heading"), class: "h6 text-muted text-uppercase") do %> <%= field_set_tag content_tag(:span, t(".signer_details.heading"), class: "h6 text-muted text-uppercase") do %>
<div class="form-row"> <div class="form-row">
<%= form.text_field :person_first_name, wrapper_class: "col-sm-3" %> <%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-3" %> <%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %> <%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :person_company, wrapper_class: "col-sm-6" %> <%= form.text_field :person_company, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %> <%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
</div> </div>
@@ -38,6 +34,7 @@
<div class="form-row"> <div class="form-row">
<%= form.text_field :filming_started_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %> <%= form.text_field :filming_started_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %>
<%= form.text_field :filming_ended_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %> <%= form.text_field :filming_ended_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %>
<%= form.text_field :filming_hours, wrapper_class: "col-sm-12" %>
</div> </div>
<% end %> <% end %>

View File

@@ -13,14 +13,10 @@
<%= field_set_tag content_tag(:span, t(".signer_details.heading"), class: "h6 text-muted text-uppercase") do %> <%= field_set_tag content_tag(:span, t(".signer_details.heading"), class: "h6 text-muted text-uppercase") do %>
<div class="form-row"> <div class="form-row">
<%= form.text_field :person_first_name, wrapper_class: "col-sm-3" %> <%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-3" %> <%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %> <%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :person_company, wrapper_class: "col-sm-6" %> <%= form.text_field :person_company, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %> <%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
</div> </div>

View File

@@ -0,0 +1,49 @@
<tr id="<%= dom_id(medical_release) %>">
<td data-behavior="select"><%= check_box_tag "medical_release_ids[]", medical_release.id, false %></td>
<td>
<% if medical_release.photo.attached? %>
<%= image_tag medium_variant(medical_release.photo), class: "img-fluid" %>
<% end %>
</td>
<td>
<%= medical_release.name %>
</td>
<td>
<%= contact_info(
address: medical_release.person_address,
phone: medical_release.person_phone,
email: medical_release.person_email
) %>
</td>
<td>
<%= notes_preview medical_release.notes.order_by_recent %>
</td>
<td id="<%= dom_id medical_release, "tags_preview" %>">
<%= tags_preview medical_release, medical_release.tags %>
</td>
<td>
<%= medical_release.signed_on %>
</td>
<td class="text-right">
<div class="btn-group">
<%= button_tag t(".actions.manage"), class: "btn btn-light btn-sm dropdown-toggle border", data: { toggle: "dropdown", boundary: "window" }, aria: { haspopup: true, expanded: false } %>
<div class="dropdown-menu dropdown-menu-right">
<% if policy(Note).new? %>
<%= link_to fa_icon("sticky-note fw", text: "Notes"), [:new, medical_release, :note], class: "dropdown-item", remote: true %>
<% end %>
<% if policy(medical_release.tags).new? %>
<%= link_to fa_icon("tags fw", text: "Tags"), [:new, medical_release, :acts_as_taggable_on_tag], class: "dropdown-item", remote: true %>
<% end %>
<% if policy(MedicalRelease).download_single? && policy(Contract).show? && (medical_release.contract.attached? || medical_release.contract_template.present?) %>
<%= link_to fa_icon("download fw", text: "Download"), [medical_release, :contracts, format: "pdf"], class: "dropdown-item", target: "_blank" %>
<% end %>
<% if policy(medical_release).destroy? %>
<%= link_to fa_icon("trash fw", text: "Delete"), medical_release, class: "dropdown-item", method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
</div>
</div>
</td>
</tr>

View File

@@ -0,0 +1,48 @@
<div class="row">
<div class="col-md-12">
<div class="d-md-flex d-sm-flex flex-sm-column flex-md-row flex-md-wrap mb-3">
<% if @medical_releases.any? && policy(MedicalRelease).tag_multiple? %>
<%= button_to_bulk_tagging(@project) %>
<% end %>
<% if @medical_releases.any? && policy(MedicalRelease).download_multiple? %>
<%= link_to "Download All", [@project, :contract_downloads, release_type: @medical_releases.name], method: :post, remote: true, class: "btn btn-light border ml-auto mr-2 mb-2", data: {
disable_with: "Please wait..." } %>
<% end %>
<%= bootstrap_form_with url: [@project, :medical_releases], method: :get, remote: true, layout: :inline, id: "search" do |form| %>
<%= form.search_field :query, hide_label: true, placeholder: t(".actions.search"), class: "rounded-pill-right", value: params[:query], prepend: form.button(fa_icon("search"), class: "btn btn-light border mb-2 rounded-pill-left") %>
<% end %>
</div>
</div>
</div>
<div class="border bg-white rounded shadow-sm pb-3 table-responsive">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th data-behavior="all-selectable"><%= check_box_tag "medical_release_ids[]", false, false %></th>
<th></th>
<th><%= MedicalRelease.human_attribute_name(:person_name) %></th>
<th><%= MedicalRelease.human_attribute_name(:contact_info) %></th>
<th><%= t(".table_headers.notes") %></th>
<th><%= t(".table_headers.tags") %></th>
<th><%= t(".table_headers.signed_at") %></th>
<th></th>
</tr>
</thead>
<tbody id="medical_releases">
<% if @medical_releases.any? %>
<%= render @medical_releases %>
<% else %>
<tr>
<td colspan="12" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="medical_releases_pagination" class="mt-3">
<%= will_paginate @medical_releases %>
</div>

View File

@@ -0,0 +1,3 @@
$("#medical_releases").html("<%= j render(@medical_releases) %>");
$("form input[type='search']").val("<%= params[:query] %>");
$("#medical_releases_pagination").html("<%= j will_paginate(@medical_releases) %>");

View File

@@ -0,0 +1,48 @@
<tr id="<%= dom_id(misc_release) %>">
<td data-behavior="select"><%= check_box_tag "misc_release_ids[]", misc_release.id, false %></td>
<td>
<% if misc_release.photo.attached? %>
<%= image_tag medium_variant(misc_release.photo), class: "img-fluid" %>
<% end %>
</td>
<td>
<%= misc_release.name %>
</td>
<td>
<%= contact_info(
address: misc_release.person_address,
phone: misc_release.person_phone,
email: misc_release.person_email
) %>
</td>
<td>
<%= notes_preview misc_release.notes.order_by_recent %>
</td>
<td id="<%= dom_id misc_release, "tags_preview" %>">
<%= tags_preview misc_release, misc_release.tags %>
</td>
<td>
<%= misc_release.signed_on %>
</td>
<td class="text-right">
<div class="btn-group">
<%= button_tag t(".actions.manage"), class: "btn btn-light btn-sm dropdown-toggle border", data: { toggle: "dropdown", boundary: "window" }, aria: { haspopup: true, expanded: false } %>
<div class="dropdown-menu dropdown-menu-right">
<% if policy(Note).new? %>
<%= link_to fa_icon("sticky-note fw", text: "Notes"), [:new, misc_release, :note], class: "dropdown-item", remote: true %>
<% end %>
<% if policy(misc_release.tags).new? %>
<%= link_to fa_icon("tags fw", text: "Tags"), [:new, misc_release, :acts_as_taggable_on_tag], class: "dropdown-item", remote: true %>
<% end %>
<% if policy(MedicalRelease).download_single? && policy(Contract).show? && (misc_release.contract.attached? || misc_release.contract_template.present?) %>
<%= link_to fa_icon("download fw", text: "Download"), [misc_release, :contracts, format: "pdf"], class: "dropdown-item", target: "_blank" %>
<% end %>
<% if policy(misc_release).destroy? %>
<%= link_to fa_icon("trash fw", text: "Delete"), misc_release, class: "dropdown-item", method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
</div>
</div>
</td>
</tr>

View File

@@ -0,0 +1,48 @@
<div class="row">
<div class="col-md-12">
<div class="d-md-flex d-sm-flex flex-sm-column flex-md-row flex-md-wrap mb-3">
<% if @misc_releases.any? && policy(MiscRelease).tag_multiple? %>
<%= button_to_bulk_tagging(@project) %>
<% end %>
<% if @misc_releases.any? && policy(MiscRelease).download_multiple? %>
<%= link_to "Download All", [@project, :contract_downloads, release_type: @misc_releases.name], method: :post, remote: true, class: "btn btn-light border ml-auto mr-2 mb-2", data: {
disable_with: "Please wait..." } %>
<% end %>
<%= bootstrap_form_with url: [@project, :misc_releases], method: :get, remote: true, layout: :inline, id: "search" do |form| %>
<%= form.search_field :query, hide_label: true, placeholder: t(".actions.search"), class: "rounded-pill-right", value: params[:query], prepend: form.button(fa_icon("search"), class: "btn btn-light border mb-2 rounded-pill-left") %>
<% end %>
</div>
</div>
</div>
<div class="border bg-white rounded shadow-sm pb-3 table-responsive">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th data-behavior="all-selectable"><%= check_box_tag "misc_release_ids[]", false, false %></th>
<th></th>
<th><%= MiscRelease.human_attribute_name(:person_name) %></th>
<th><%= MiscRelease.human_attribute_name(:contact_info) %></th>
<th><%= t(".table_headers.notes") %></th>
<th><%= t(".table_headers.tags") %></th>
<th><%= t(".table_headers.signed_at") %></th>
<th></th>
</tr>
</thead>
<tbody id="misc_releases">
<% if @misc_releases.any? %>
<%= render @misc_releases %>
<% else %>
<tr>
<td colspan="12" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="misc_releases_pagination" class="mt-3">
<%= will_paginate @misc_releases %>
</div>

View File

@@ -0,0 +1,3 @@
$("#misc_releases").html("<%= j render(@misc_releases) %>");
$("form input[type='search']").val("<%= params[:query] %>");
$("#misc_releases_pagination").html("<%= j will_paginate(@misc_releases) %>");

View File

@@ -1,6 +1,6 @@
<%= bootstrap_form_with model: project, local: true do |form| %> <%= bootstrap_form_with model: project, local: true do |form| %>
<%= form.text_field :name %> <%= form.text_field :name %>
<%= form.select :predefined_client_name, options_for_select(options_for_predefined_client_name_select, selected_project_client_value(project)), {}, data: { toggle: "collapse-select", target: "#other_client", show_values: [:other] }, class: "form-control custom-select" %> <%= form.select :predefined_client_name, options_for_select(options_for_predefined_client_name_select, selected_project_client_value(project)), {}, data: { toggle: "collapse-select", target_show_values_mapping: { "#other_client": [:other] } }, class: "form-control custom-select" %>
<div id="other_client" style="<%='display: none' if selected_project_client_value(project) != 'other'%>"> <div id="other_client" style="<%='display: none' if selected_project_client_value(project) != 'other'%>">
<%= form.text_field :client_name, placeholder: true %> <%= form.text_field :client_name, placeholder: true %>
<%= form.form_group do %> <%= form.form_group do %>

View File

@@ -15,12 +15,12 @@
<%= card_field_set_tag t(".acquired_media_info.heading") do %> <%= card_field_set_tag t(".acquired_media_info.heading") do %>
<div class="form-row"> <div class="form-row">
<%= form.text_field :name, required: true, wrapper_class: "col-12", label: 'Licensor ("Owner")' %> <%= form.text_field :name, required: true, wrapper_class: "col-12" %>
</div> </div>
<div class="form-row"> <div class="form-row">
<%= form.text_area :description, wrapper_class: "col-12" %> <%= form.text_area :description, required: true, wrapper_class: "col-12" %>
</div> </div>
<%= form.form_group :categories, label: { text: "Categories" } do %> <%= form.form_group :categories, label: { text: "Licensed property type" } do %>
<% AcquiredMediaRelease::CATEGORIES.each do |category| %> <% AcquiredMediaRelease::CATEGORIES.each do |category| %>
<%= form.check_box :categories, { multiple: true, label: category }, category, false %> <%= form.check_box :categories, { multiple: true, label: category }, category, false %>
<% end %> <% end %>
@@ -31,20 +31,19 @@
<%= card_field_set_tag t(".personal_info.heading") do %> <%= card_field_set_tag t(".personal_info.heading") do %>
<div class="form-row"> <div class="form-row">
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %> <%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_phone, wrapper_class: "col-sm-6", label: 'Phone' %> <%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_fax, wrapper_class: "col-sm-6", label: 'Fax' %> <%= form.text_field :person_title, required: true, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, required: true, wrapper_class: "col-sm-6", label: 'Phone' %>
<%= form.email_field :person_email, required: true, wrapper_class: "col-sm-6", label: 'Email' %>
<%= form.text_field :person_fax, required: true, wrapper_class: "col-sm-6", label: 'Fax' %>
</div> </div>
<%= render "shared/address_fields", form: form, subject: "person" %> <%= render "shared/address_fields", form: form, required: true, subject: "person" %>
<% end %> <% end %>
<hr> <hr>
<%= card_field_set_tag t(".files.heading") do %> <%= card_field_set_tag t(".files.heading") do %>
<div class="alert alert-warning text-center text-md-left">
<%= fa_icon "warning" %>
<strong>For optimal accuracy, please ensure video file names and photo file names match the source file name in the editing sequence.</strong>
</div>
<%= render "shared/file_infos_dropzone", form: form, releasable: @acquired_media_release %> <%= render "shared/file_infos_dropzone", form: form, releasable: @acquired_media_release %>
<% end %> <% end %>

View File

@@ -30,13 +30,13 @@
<div class="form-row"> <div class="form-row">
<%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %> <%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %> <%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :person_phone, required: true, wrapper_class: "col-sm-6" %>
</div> </div>
<div class="form-row"> <div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %> <%= form.email_field :person_email, required: true, wrapper_class: "col-sm-6" %>
<%= form.date_field :person_date_of_birth, wrapper_class: "col-sm-6", placeholder: Date.current %> <%= form.date_field :person_date_of_birth, required: true, wrapper_class: "col-sm-6", placeholder: Date.current %>
<%= form.text_field :person_address, wrapper_class: "col-sm-6" %>
</div> </div>
<%= render "shared/address_fields", form: form, subject: "person", required: true %>
<% end %> <% end %>
<%= card_field_set_tag t(".photo.heading") do %> <%= card_field_set_tag t(".photo.heading") do %>
@@ -57,7 +57,7 @@
<%= form.hidden_field :person_photo, value: form.object.person_photo.signed_id if @appearance_release.person_photo.attached? %> <%= form.hidden_field :person_photo, value: form.object.person_photo.signed_id if @appearance_release.person_photo.attached? %>
<%= form.file_field :person_photo, hide_label: true, data: { ujs_target: "person-photo-input" }, accept: @appearance_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %> <%= form.file_field :person_photo, hide_label: true, data: { ujs_target: "person-photo-input" }, accept: @appearance_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %>
</div> </div>
<%= button_tag t(".photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "take-person-photo" } %> <%= button_tag t(".photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "trigger-click", target: "[data-ujs-target=person-photo-input]" } %>
</div> </div>
<p class="p-2 font-weight-bold"> <p class="p-2 font-weight-bold">
<%= fa_icon "arrow-up", text: t(".photo.camera_instructions_html") %><br> <%= fa_icon "arrow-up", text: t(".photo.camera_instructions_html") %><br>
@@ -74,11 +74,10 @@
<div class="form-row"> <div class="form-row">
<%= form.text_field :guardian_first_name, required: @appearance_release.minor?, wrapper_class: "col-sm-3" %> <%= form.text_field :guardian_first_name, required: @appearance_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_last_name, required: @appearance_release.minor?, wrapper_class: "col-sm-3" %> <%= form.text_field :guardian_last_name, required: @appearance_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :guardian_phone, required: @appearance_release.minor?, wrapper_class: "col-sm-6" %>
</div> <%= form.text_field :guardian_email, required: @appearance_release.minor?, wrapper_class: "col-sm-6" %>
<div class="form-row">
<%= form.text_field :guardian_address, wrapper_class: "col-sm-6" %>
</div> </div>
<%= render "shared/address_fields", form: form, subject: "guardian", required: @appearance_release.minor? %>
<% end %> <% end %>
<hr> <hr>
@@ -99,9 +98,50 @@
<% end %> <% end %>
<div class="hidden-file-input"> <div class="hidden-file-input">
<%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if @appearance_release.guardian_photo.attached? %> <%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if @appearance_release.guardian_photo.attached? %>
<%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, accept: @appearance_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %> <%= form.file_field :guardian_photo, required: @appearance_release.minor?, hide_label: true, data: { ujs_target: "guardian-photo-input" }, accept: @appearance_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %>
</div> </div>
<%= button_tag t(".photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "take-guardian-photo" } %> <%= button_tag t(".photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "trigger-click", target: "[data-ujs-target=guardian-photo-input]" } %>
</div>
<p class="p-2 font-weight-bold">
<%= fa_icon "arrow-up", text: t(".photo.camera_instructions_html") %><br>
<small class="text-muted"><%= t ".photo.warning" %></small>
</p>
</div>
<% end %>
<hr>
<%= card_field_set_tag t(".guardian_2_info.heading") do %>
<div class="form-row">
<%= form.text_field :guardian_2_first_name, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_2_last_name, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_2_phone, wrapper_class: "col-sm-6" %>
<%= form.text_field :guardian_2_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian_2" %>
<% end %>
<hr>
<%= card_field_set_tag t(".guardian_2_photo.heading") do %>
<div class="alert alert-warning font-weight-bold"><%= t ".guardian_2_photo.instructions" %></div>
<div class="text-center">
<div class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-2-photo-input]">
<div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center">
<span><%= t ".photo.no_photo" %></span>
</div>
</div>
<div class="d-inline-block text-left">
<% if @appearance_release.guardian_2_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("[data-behavior=guardian-photo-preview]", "<%= url_for(@appearance_release.guardian_2_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %>
<% end %>
<div class="hidden-file-input">
<%= form.hidden_field :guardian_2_photo, value: form.object.guardian_2_photo.signed_id if @appearance_release.guardian_2_photo.attached? %>
<%= form.file_field :guardian_2_photo, hide_label: true, data: { ujs_target: "guardian-2-photo-input" }, accept: @appearance_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %>
</div>
<%= button_tag t(".photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "trigger-click", target: "[data-ujs-target=guardian-2-photo-input]" } %>
</div> </div>
<p class="p-2 font-weight-bold"> <p class="p-2 font-weight-bold">
<%= fa_icon "arrow-up", text: t(".photo.camera_instructions_html") %><br> <%= fa_icon "arrow-up", text: t(".photo.camera_instructions_html") %><br>

View File

@@ -1,4 +1,4 @@
<%= bootstrap_form_for model, url: broadcast_url(token: token), layout: :inline, remote: true do |form| %> <%= bootstrap_form_for model, url: broadcast_url(token: token), layout: :inline, remote: true do |form| %>
<%= form.file_field :files, direct_upload: true, multiple: true, accept: "*", hide_label: true, wrapper_class: "w-65 mr-2" %> <%= form.file_field :files, direct_upload: true, multiple: true, accept: "*", hide_label: true, required: true, wrapper_class: "w-65 mr-2", id: "broadcast_files_#{token}" %>
<%= form.button fa_icon("upload", text: "Add File"), class: "btn btn-primary", type: :submit, data: { disable_with: fa_icon("spinner", text: "Adding File") } %> <%= form.button fa_icon("upload", text: "Add File"), class: "btn btn-primary", type: :submit, data: { disable_with: fa_icon("spinner", text: "Adding File") } %>
<% end %> <% end %>

View File

@@ -1,9 +1,9 @@
$("#broadcast_file_form").html("<%= j render(partial: "public/broadcasts/file_form", locals: { model: [@project, @broadcast], token: @broadcast.token }) %>"); $("#broadcast_file_form_<%= @broadcast.token %>").html("<%= j render(partial: "public/broadcasts/file_form", locals: { model: [@project, @broadcast], token: @broadcast.token }) %>");
var file_id = "#<%= dom_id(@files.first) %>" var file_id = "#<%= dom_id(@files.first) %>"
if ($("#broadcast_file_list").has(file_id).length == 0) { if ($("#broadcast_file_list_<%= @broadcast.token %>").has(file_id).length == 0) {
$("#broadcast_file_list").html("<%= j render(partial: "broadcasts/file", collection: @files) %>"); $("#broadcast_file_list_<%= @broadcast.token %>").html("<%= j render(partial: "broadcasts/file", collection: @files) %>");
$("#broadcast_files_pagination").html("<%= j will_paginate(@files) %>"); $("#broadcast_files_pagination_<%= @broadcast.token %>").html("<%= j will_paginate(@files) %>");
} }
bsCustomFileInput.init(); bsCustomFileInput.init();

View File

@@ -17,25 +17,21 @@
<div class="form-row"> <div class="form-row">
<%= form.text_field :name, required: true, wrapper_class: "col-12" %> <%= form.text_field :name, required: true, wrapper_class: "col-12" %>
</div> </div>
<%= render "shared/address_fields", form: form, subject: "" %> <%= render "shared/address_fields", form: form, required: true, subject: "" %>
<% end %> <% end %>
<hr> <hr>
<%= card_field_set_tag t(".contact_info.heading") do %> <%= card_field_set_tag t(".contact_info.heading") do %>
<div class="form-row"> <div class="form-row">
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %> <%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %> <%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :person_phone, required: true, wrapper_class: "col-sm-6" %>
<%= form.email_field :person_email, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_company, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, required: true, wrapper_class: "col-sm-6" %>
</div> </div>
<div class="form-row"> <%= render "shared/address_fields", form: form, required: true, subject: "person" %>
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :person_company, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>
<% end %> <% end %>
<hr> <hr>
@@ -43,11 +39,16 @@
<%= card_field_set_tag t(".filming_info.heading") do %> <%= card_field_set_tag t(".filming_info.heading") do %>
<div class="form-row"> <div class="form-row">
<%= form.text_field :filming_started_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %> <%= form.text_field :filming_started_on, required: true, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %>
<%= form.text_field :filming_ended_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %> <%= form.text_field :filming_ended_on, required: true, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %>
<%= form.text_field :filming_hours, required: true, wrapper_class: "col-sm-12" %>
</div> </div>
<% end %> <% end %>
<%= card_field_set_tag t(".photos.heading") do %>
<%= render "shared/photos_dropzone_fields", form: form, release: @location_release %>
<% end %>
<%= card_field_set_tag t(".signature.heading") do %> <%= card_field_set_tag t(".signature.heading") do %>
<%= render "shared/signature_fields", form: form, instruction: 'An Authorized Signatory' %> <%= render "shared/signature_fields", form: form, instruction: 'An Authorized Signatory' %>
<% end %> <% end %>

View File

@@ -18,24 +18,24 @@
<%= form.text_field :name, required: true, wrapper_class: "col-12" %> <%= form.text_field :name, required: true, wrapper_class: "col-12" %>
</div> </div>
<div class="form-row"> <div class="form-row">
<%= form.text_area :description, placeholder: true, wrapper_class: "col-sm-12", rows: 6 %> <%= form.text_area :description, required: true, placeholder: true, wrapper_class: "col-sm-12", rows: 6 %>
</div> </div>
<% end %> <% end %>
<%= card_field_set_tag t(".contact_info.heading") do %> <%= card_field_set_tag t(".contact_info.heading") do %>
<div class="form-row"> <div class="form-row">
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %> <%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %> <%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :person_phone, required: true, wrapper_class: "col-sm-6" %>
<%= form.email_field :person_email, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_company, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, required: true, wrapper_class: "col-sm-6" %>
</div> </div>
<div class="form-row"> <%= render "shared/address_fields", form: form, subject: "person", required: true %>
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %> <% end %>
</div>
<div class="form-row"> <%= card_field_set_tag t(".photo.heading") do %>
<%= form.text_field :person_company, wrapper_class: "col-sm-6" %> <%= render "shared/photos_dropzone_fields", form: form, release: @material_release %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>
<% end %> <% end %>
<hr> <hr>

View File

@@ -0,0 +1 @@
<p class="alert alert-success p-3 lead text-center">Your release was successfully submitted. Thank you.</p>

View File

@@ -0,0 +1,158 @@
<div class="card shadow-sm">
<div class="card-body">
<%= errors_summary_for @medical_release %>
<%= bootstrap_form_with model: [@account, @project, @contract_template, @medical_release], local: true, validation_context: :native do |form| %>
<div class="alert alert-warning font-weight-bold"><%= t ".instructions_html", name: @project.name %></div>
<%= card_field_set_tag t(".legal.heading") do %>
<p><%= @contract_template.body %></p>
<% if @contract_template.fee? %>
<p>
Fee <span class="font-weight-bold text-success"><%= number_to_currency @contract_template.fee %></span>
</p>
<% end %>
<% end %>
<hr>
<% unless @contract_template.guardian_clause.blank? %>
<%= form.form_group :minor do %>
<%= form.check_box :minor, label: t("helpers.label.medical_release.minor"), data: { target: "[data-ujs-target=guardian-fields]", toggle: "collapse" } %>
<% end %>
<%= card_field_set_tag t(".guardian_clause.heading") do %>
<p><%= @contract_template.guardian_clause %></p>
<% end %>
<hr>
<% end %>
<% if (1..MedicalRelease::NUMBER_OF_CUSTOM_FIELDS).map {|n| @contract_template.public_send("question_#{n}_text").presence }.compact.any? %>
<%= card_field_set_tag t(".questionnaire.heading") do %>
<% (1..MedicalRelease::NUMBER_OF_CUSTOM_FIELDS).each do |n| %>
<% if @contract_template.public_send("question_#{n}_text").present? %>
<div class="form-row">
<%= form.text_area "question_#{n}_answer", wrapper_class: "col-sm-12", label: @contract_template.public_send("question_#{n}_text") %>
</div>
<% end %>
<% end %>
<% end %>
<hr>
<% end %>
<%= card_field_set_tag t(".personal_info.heading") do %>
<div class="alert alert-warning font-weight-bold"><%= t ".personal_info.instructions" %></div>
<div class="form-row">
<%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>
<% end %>
<hr>
<%= card_field_set_tag t(".photo.heading") do %>
<%= render "shared/photos_dropzone_fields", form: form, release: @medical_release %>
<% end %>
<% unless @contract_template.guardian_clause.blank? %>
<div class="<%= class_string("collapse" => !@medical_release.minor?) %>" data-ujs-target="guardian-fields">
<%= card_field_set_tag t(".guardian_info.heading") do %>
<div class="form-row">
<%= form.text_field :guardian_first_name, required: @medical_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_last_name, required: @medical_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, required: @medical_release.minor?, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :guardian_email, required: @medical_release.minor?, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian", required: @medical_release.minor? %>
<% end %>
<hr>
<%= card_field_set_tag t(".guardian_photo.heading") do %>
<div class="alert alert-warning font-weight-bold"><%= t ".guardian_photo.instructions" %></div>
<div class="text-center">
<div class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-photo-input]">
<div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center">
<span><%= t ".photo.no_photo" %></span>
</div>
</div>
<div class="d-inline-block text-left">
<% if @medical_release.guardian_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("[data-behavior=guardian-photo-preview]", "<%= url_for(@medical_release.guardian_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %>
<% end %>
<div class="hidden-file-input">
<%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if @medical_release.guardian_photo.attached? %>
<%= form.file_field :guardian_photo, required: @medical_release.minor?, hide_label: true, data: { ujs_target: "guardian-photo-input" }, accept: @medical_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %>
</div>
<%= button_tag t(".photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "take-guardian-photo" } %>
</div>
<p class="p-2 font-weight-bold">
<%= fa_icon "arrow-up", text: t(".photo.camera_instructions_html") %><br>
<small class="text-muted"><%= t ".photo.warning" %></small>
</p>
</div>
<% end %>
<hr>
<%= card_field_set_tag t(".guardian_2_info.heading") do %>
<div class="form-row">
<%= form.text_field :guardian_2_first_name, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_2_last_name, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_2_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :guardian_2_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian_2" %>
<% end %>
<hr>
<%= card_field_set_tag t(".guardian_2_photo.heading") do %>
<div class="alert alert-warning font-weight-bold"><%= t ".guardian_2_photo.instructions" %></div>
<div class="text-center">
<div class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-2-photo-input]">
<div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center">
<span><%= t ".photo.no_photo" %></span>
</div>
</div>
<div class="d-inline-block text-left">
<% if @medical_release.guardian_2_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("[data-behavior=guardian-photo-preview]", "<%= url_for(@medical_release.guardian_2_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %>
<% end %>
<div class="hidden-file-input">
<%= form.hidden_field :guardian_2_photo, value: form.object.guardian_2_photo.signed_id if @medical_release.guardian_2_photo.attached? %>
<%= form.file_field :guardian_2_photo, hide_label: true, data: { ujs_target: "guardian-2-photo-input" }, accept: @medical_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %>
</div>
<%= button_tag t(".photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "take-guardian-2-photo" } %>
</div>
<p class="p-2 font-weight-bold">
<%= fa_icon "arrow-up", text: t(".photo.camera_instructions_html") %><br>
<small class="text-muted"><%= t ".photo.warning" %></small>
</p>
</div>
<% end %>
<hr>
</div>
<% end %>
<%= card_field_set_tag t(".signature.heading") do %>
<%= render "shared/signature_fields", form: form %>
<% end %>
<div class="mt-5">
<%= form.button t("shared.submit_release_short"), class: "btn btn-block btn-lg btn-success", data: { disable_with: t("shared.disable_with") } %>
</div>
<% end %>
</div>
</div>

View File

@@ -0,0 +1 @@
<p class="alert alert-success p-3 lead text-center">Your release was successfully submitted. Thank you.</p>

View File

@@ -0,0 +1,97 @@
<div class="card shadow-sm">
<div class="card-body">
<%= errors_summary_for @misc_release %>
<%= bootstrap_form_with model: [@account, @project, @contract_template, @misc_release], local: true, validation_context: :native do |form| %>
<div class="alert alert-warning font-weight-bold"><%= t ".instructions_html", name: @project.name %></div>
<%= card_field_set_tag t(".legal.heading") do %>
<p><%= @contract_template.body %></p>
<% end %>
<hr>
<% unless @contract_template.guardian_clause.blank? %>
<%= form.form_group :minor do %>
<%= form.check_box :minor, label: t("helpers.label.appearance_release.minor"), data: { target: "[data-ujs-target=guardian-fields]", toggle: "collapse" } %>
<% end %>
<%= card_field_set_tag t(".guardian_clause.heading") do %>
<p><%= @contract_template.guardian_clause %></p>
<% end %>
<hr>
<% end %>
<%= card_field_set_tag t(".personal_info.heading") do %>
<div class="alert alert-warning font-weight-bold"><%= t ".personal_info.instructions" %></div>
<div class="form-row">
<%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>
<% end %>
<hr>
<%= card_field_set_tag t(".photo.heading") do %>
<%= render "shared/photos_dropzone_fields", form: form, release: @misc_release %>
<% end %>
<% unless @contract_template.guardian_clause.blank? %>
<div class="<%= class_string("collapse" => !@misc_release.minor?) %>" data-ujs-target="guardian-fields">
<%= card_field_set_tag t(".guardian_info.heading") do %>
<div class="form-row">
<%= form.text_field :guardian_first_name, required: @misc_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_last_name, required: @misc_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :guardian_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian" %>
<% end %>
<hr>
<%= card_field_set_tag t(".guardian_photo.heading") do %>
<div class="alert alert-warning font-weight-bold"><%= t ".guardian_photo.instructions" %></div>
<div class="text-center">
<div class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-photo-input]">
<div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center">
<span><%= t ".guardian_photo.no_photo" %></span>
</div>
</div>
<div class="d-inline-block text-left">
<% if @misc_release.guardian_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("[data-behavior=guardian-photo-preview]", "<%= url_for(@misc_release.guardian_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %>
<% end %>
<div class="hidden-file-input">
<%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if @misc_release.guardian_photo.attached? %>
<%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, accept: @misc_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %>
</div>
<%= button_tag t(".guardian_photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "take-guardian-photo" } %>
</div>
<p class="p-2 font-weight-bold">
<%= fa_icon "arrow-up", text: t(".guardian_photo.camera_instructions_html") %><br>
<small class="text-muted"><%= t ".guardian_photo.warning" %></small>
</p>
</div>
<% end %>
</div>
<hr>
<% end %>
<%= card_field_set_tag t(".signature.heading") do %>
<%= render "shared/signature_fields", form: form %>
<% end %>
<div class="mt-5">
<%= form.button t("shared.submit_release_long"), class: "btn btn-block btn-lg btn-success", data: { disable_with: t("shared.disable_with") } %>
</div>
<% end %>
</div>
</div>

View File

@@ -78,7 +78,7 @@
<%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if @talent_release.guardian_photo.attached? %> <%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if @talent_release.guardian_photo.attached? %>
<%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, accept: @talent_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %> <%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, accept: @talent_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %>
</div> </div>
<%= button_tag t(".guardian_photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "take-guardian-photo" } %> <%= button_tag t(".guardian_photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "trigger-click", target: "[data-ujs-target=guardian-photo-input]" } %>
</div> </div>
<p class="p-2 font-weight-bold"> <p class="p-2 font-weight-bold">
<%= fa_icon "arrow-up", text: t(".guardian_photo.camera_instructions_html") %><br> <%= fa_icon "arrow-up", text: t(".guardian_photo.camera_instructions_html") %><br>

View File

@@ -1,16 +1,17 @@
<% field_name_prefix = subject.present? ? "#{subject}_" : "" %> <% field_name_prefix = subject.present? ? "#{subject}_" : "" %>
<% required = required || false %>
<div class="form-row"> <div class="form-row">
<%= form.text_field "#{field_name_prefix}address_street1", wrapper_class: "col-sm-6" %> <%= form.text_field "#{field_name_prefix}address_street1", required: required, wrapper_class: "col-sm-6" %>
<%= form.text_field "#{field_name_prefix}address_street2", wrapper_class: "col-sm-6" %> <%= form.text_field "#{field_name_prefix}address_street2", wrapper_class: "col-sm-6" %>
</div> </div>
<div class="form-row"> <div class="form-row">
<%= form.text_field "#{field_name_prefix}address_city", wrapper_class: "col-sm-6" %> <%= form.text_field "#{field_name_prefix}address_city", required: required, wrapper_class: "col-sm-6" %>
<%= form.text_field "#{field_name_prefix}address_state", wrapper_class: "col-sm-3" %> <%= form.text_field "#{field_name_prefix}address_state", required: required, wrapper_class: "col-sm-3" %>
<%= form.text_field "#{field_name_prefix}address_zip", wrapper_class: "col-sm-3" %> <%= form.text_field "#{field_name_prefix}address_zip", required: required, wrapper_class: "col-sm-3" %>
</div> </div>
<%= form.form_group "#{field_name_prefix}address_country" do %> <%= form.form_group "#{field_name_prefix}address_country" do %>
<%= form.label "#{field_name_prefix}address_country" %> <%= form.label "#{field_name_prefix}address_country" %>
<%= form.country_select "#{field_name_prefix}address_country", { priority: %w(US CA), prompt: true }, class: "form-control custom-select" %> <%= form.country_select "#{field_name_prefix}address_country", { selected: 'US', priority: %w(US CA), prompt: true }, class: "form-control custom-select" %>
<% end %> <% end %>

View File

@@ -0,0 +1,5 @@
<% (1..MedicalRelease::NUMBER_OF_CUSTOM_FIELDS).each do |n| %>
<div class="form-row">
<%= form.text_area "question_#{n}_text", wrapper_class: "col-sm-12" %>
</div>
<% end%>

View File

@@ -1,4 +1,6 @@
require 'zoom' require 'zoom'
require 'zoom_gateway'
unless Rails.env.test? unless Rails.env.test?
Zoom.configure do |c| Zoom.configure do |c|
c.api_key = ENV['ZOOM_API_KEY'] c.api_key = ENV['ZOOM_API_KEY']

View File

@@ -60,6 +60,10 @@ en:
activerecord: activerecord:
attributes: attributes:
appearance_release: appearance_release:
guardian_2_address: Guardian 2 address
guardian_2_email: Guardian 2 email
guardian_2_name: Guardian 2 name
guardian_2_phone: Guardian 2 phone
person_address: Address person_address: Address
person_email: Email person_email: Email
person_name: Name person_name: Name
@@ -112,15 +116,22 @@ en:
no_photos: Needs Photo no_photos: Needs Photo
create: create:
failed_import: Failed to create appearance release for files listed below failed_import: Failed to create appearance release for files listed below
matching_started: Matching started
no_attachments: Failed to import - no attachments no_attachments: Failed to import - no attachments
edit: edit:
heading: Edit Appearance Release heading: Edit Appearance Release
form: form:
contract_and_rights: contract_and_rights:
heading: 2 of 3 Contract & Exploitable Rights heading: 2 of 3 Contract & Exploitable Rights
guardian_2_info:
heading: Second Guardian Information (if company requires)
guardian_info:
heading: Guardian Information
person_details: person_details:
heading: 1 of 3 Person Details heading: 1 of 3 Person Details
photos: photos:
guardian_2_photo:
heading: Second Guardian Photo
guardian_photo: guardian_photo:
heading: Guardian Photo heading: Guardian Photo
heading: 3 of 3 Photo heading: 3 of 3 Photo
@@ -141,6 +152,8 @@ en:
shared: shared:
imported_appearance_release_contract_name: Imported Contract imported_appearance_release_contract_name: Imported Contract
imported_appearance_release_headshot_name: Imported Headshot imported_appearance_release_headshot_name: Imported Headshot
incomplete_match: Incomplete Match
matched_import: Complete Match
type_filter_actions: type_filter_actions:
all_releases: All Releases all_releases: All Releases
complete_releases: Complete Releases complete_releases: Complete Releases
@@ -212,12 +225,15 @@ en:
archived_failure: Failed to archive the release template archived_failure: Failed to archive the release template
archived_notice: The release template has been archived archived_notice: The release template has been archived
form: form:
custom_fields:
heading: Medical Questionnaire
instructions: Please list the questions you wish the signer to answer. Any unused question fields will be hidden.
exploitable_rights: exploitable_rights:
heading: 2 of 3 Exploitable Rights heading: Exploitable Rights
legal: legal:
heading: 3 of 3 Legal heading: Legal
release_info: release_info:
heading: 1 of 3 Release Info heading: Release Info
index: index:
actions: actions:
import: Import Release Template import: Import Release Template
@@ -230,7 +246,10 @@ en:
new: new:
heading: New Release Template heading: New Release Template
contracts: contracts:
medical_questionnaire:
heading: Medical Questionnaire
photos: photos:
guardian_2_photo_heading: Second guardian photo
guardian_photo_heading: Guardian photo guardian_photo_heading: Guardian photo
heading: heading:
one: Photo one: Photo
@@ -298,6 +317,9 @@ en:
notice: The release has been updated notice: The release has been updated
helpers: helpers:
help: help:
contract_template:
fee: Leave at $0.00 for no-fee
guardian_clause: Leave blank if not required for this contract
video: video:
audio_only_edl_file: If you do not upload an Audio Only EDL, the software will not generate a BiG Music Cue Sheet. audio_only_edl_file: If you do not upload an Audio Only EDL, the software will not generate a BiG Music Cue Sheet.
edl_file: Please follow our directions on exporting the All Tracks EDL. Failure to do so could result in inaccurate and incomplete reporting. edl_file: Please follow our directions on exporting the All Tracks EDL. Failure to do so could result in inaccurate and incomplete reporting.
@@ -305,6 +327,8 @@ en:
graphics_only_edl_file: If you do not upload a Graphics Only EDL, the software will not generate a Graphics Cue List. graphics_only_edl_file: If you do not upload a Graphics Only EDL, the software will not generate a Graphics Cue List.
label: label:
acquired_media_release: acquired_media_release:
description: Description of property
name: Name of property
person_address: Address person_address: Address
person_address_city: City person_address_city: City
person_address_country: Country person_address_country: Country
@@ -314,29 +338,62 @@ en:
person_address_zip: Zip code person_address_zip: Zip code
person_company: Company person_company: Company
person_email: Email address person_email: Email address
person_first_name: Licensor/Owner first name
person_last_name: Licensor/Owner last name
person_name: Name person_name: Name
person_phone: Phone number person_phone: Phone number
person_title: Title person_title: Title
appearance_release: appearance_release:
guardian_2_address_city: Guardian 2 city
guardian_2_address_country: Guardian 2 country
guardian_2_address_state: Guardian 2 state
guardian_2_address_street1: Guardian 2 address
guardian_2_address_street2: Guardian 2 address (Line 2)
guardian_2_address_zip: Guardian 2 zip code
guardian_2_email: Guardian 2 email
guardian_2_first_name: Guardian 2 first name
guardian_2_last_name: Guardian 2 last name
guardian_2_phone: Guardian 2 phone
guardian_address_city: Guardian city
guardian_address_country: Guardian country
guardian_address_state: Guardian state
guardian_address_street1: Guardian address
guardian_address_street2: Guardian address (Line 2)
guardian_address_zip: Guardian zip code
minor: Is the person a minor? minor: Is the person a minor?
person_address: Address person_address_city: City
person_address_country: Country
person_address_state: State
person_address_street1: Address
person_address_street2: Address (Line 2)
person_address_zip: Zip code
person_date_of_birth: Date of birth
person_email: Email address person_email: Email address
person_first_name: First name
person_last_name: Last name
person_name: Name person_name: Name
person_phone: Phone number person_phone: Phone number
location_release: location_release:
address_city: City address_city: City
address_country: Country address_country: Country
address_state: State address_state: State
address_street1: Address address_street1: Address of Property
address_street2: Address (Line 2) address_street2: Address (Line 2)
address_zip: Zip code address_zip: Zip code
filming_ended_on: Filming end date
filming_started_on: Filming start date
name: Name of property
person_address_city: City person_address_city: City
person_address_country: Country person_address_country: Country
person_address_state: State person_address_state: State
person_address_street1: Address person_address_street1: Address
person_address_street2: Address (Line 2) person_address_street2: Address (Line 2)
person_address_zip: Zip code person_address_zip: Zip code
person_first_name: Owner first name
person_last_name: Owner last name
material_release: material_release:
description: Description of licensed material
name: Name of licensed material
person_address: Address person_address: Address
person_address_city: City person_address_city: City
person_address_country: Country person_address_country: Country
@@ -346,9 +403,45 @@ en:
person_address_zip: Zip code person_address_zip: Zip code
person_company: Company person_company: Company
person_email: Email address person_email: Email address
person_first_name: Licensor/Owner first name
person_last_name: Licensor/Owner last name
person_name: Name person_name: Name
person_phone: Phone number person_phone: Phone number
person_title: Title person_title: Title
medical_release:
guardian_2_address_city: Guardian 2 city
guardian_2_address_country: Guardian 2 country
guardian_2_address_state: Guardian 2 state
guardian_2_address_street1: Guardian 2 address
guardian_2_address_street2: Guardian 2 address (Line 2)
guardian_2_address_zip: Guardian 2 zip code
guardian_2_email: Guardian 2 email
guardian_2_first_name: Guardian 2 first name
guardian_2_last_name: Guardian 2 last name
guardian_2_phone: Guardian 2 phone
guardian_address_city: Guardian city
guardian_address_country: Guardian country
guardian_address_state: Guardian state
guardian_address_street1: Guardian address
guardian_address_street2: Guardian address (Line 2)
guardian_address_zip: Guardian zip code
guardian_email: Guardian email
guardian_first_name: Guardian first name
guardian_last_name: Guardian last name
guardian_phone: Guardian phone
minor: Is the person a minor?
person_address_city: City
person_address_country: Country
person_address_state: State
person_address_street1: Address
person_address_street2: Address (Line 2)
person_address_zip: Zip code
person_date_of_birth: Date of birth
person_email: Email address
person_first_name: First name
person_last_name: Last name
person_name: Name
person_phone: Phone number
music_release: music_release:
person_address: Address person_address: Address
person_address_city: City person_address_city: City
@@ -542,9 +635,10 @@ en:
location_details: location_details:
heading: 1 of 4 Location Details heading: 1 of 4 Location Details
photos: photos:
dropzone_label: Tap to take a photo of the Property (optional)
heading: 4 of 4 Photos heading: 4 of 4 Photos
signer_details: signer_details:
heading: 2 of 4 Signer Details heading: 2 of 4 Owner Details
index: index:
actions: actions:
new: Import Release new: Import Release
@@ -576,9 +670,10 @@ en:
material_details: material_details:
heading: 1 of 3 Material Details heading: 1 of 3 Material Details
photos: photos:
dropzone_label: Tap to take a photo of Licensed Material (optional)
heading: 4 of 4 Photos heading: 4 of 4 Photos
signer_details: signer_details:
heading: 2 of 4 Signer Details heading: 2 of 4 Licensor/Owner Details
index: index:
actions: actions:
new: Import Release new: Import Release
@@ -596,6 +691,34 @@ en:
heading: Import Material Release (Products / Logos) heading: Import Material Release (Products / Logos)
update: update:
notice: The material release has been updated notice: The material release has been updated
medical_releases:
destroy:
alert: The medical release has been deleted
index:
actions:
search: Search
empty: Medical releases will appear here
table_headers:
notes: Notes
signed_at: Date Signed
tags: Tags
medical_release:
actions:
manage: Manage
misc_releases:
destroy:
alert: The misc release has been deleted
index:
actions:
search: Search
empty: Misc Releases will appear here
table_headers:
notes: Notes
signed_at: Date Signed
tags: Tags
misc_release:
actions:
manage: Manage
music_releases: music_releases:
create: create:
notice: The music release has been created notice: The music release has been created
@@ -701,6 +824,8 @@ en:
label: Which release categories do you require for this project? label: Which release categories do you require for this project?
location_release: Location Releases location_release: Location Releases
material_release: Material Releases (Products / Logos) material_release: Material Releases (Products / Logos)
medical_release: Medical Releases
misc_release: Misc Releases
music_release: Music Releases (Original Music) music_release: Music Releases (Original Music)
talent_release: Talent Releases talent_release: Talent Releases
index: index:
@@ -727,6 +852,8 @@ en:
downloads: Downloads downloads: Downloads
location_release: Location Releases (%{count}) location_release: Location Releases (%{count})
material_release: Material Releases (%{count}) material_release: Material Releases (%{count})
medical_release: Medical Releases (%{count})
misc_release: Misc Releases (%{count})
music_release: Music Releases (%{count}) music_release: Music Releases (%{count})
report: Reports report: Reports
talent_release: Talent Releases (%{count}) talent_release: Talent Releases (%{count})
@@ -741,9 +868,7 @@ en:
legal: legal:
heading: Legal heading: Legal
personal_info: personal_info:
heading: Person Details heading: Licensor/Owner Contact Information
personal_info:
heading: Signer's Contact Information
signature: signature:
heading: Signature heading: Signature
appearance_releases: appearance_releases:
@@ -751,6 +876,12 @@ en:
notice: Your release has been signed. Thank you! notice: Your release has been signed. Thank you!
new: new:
cancel: Cancel cancel: Cancel
guardian_2_info:
heading: Second Guardian Information (if company requires)
guardian_2_photo:
heading: Second Guardian Photo
instructions: >
Lastly, it's time for second guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese!
guardian_clause: guardian_clause:
heading: Guardian Clause heading: Guardian Clause
guardian_info: guardian_info:
@@ -760,35 +891,40 @@ en:
instructions: > instructions: >
Lastly, it's time for guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese! Lastly, it's time for guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese!
instructions_html: > instructions_html: >
Congrats in appearing on <em>%{name}</em>. Below is the appearance release form. After scrolling down and reading the appearance release form, please enter your personal information, take a selfie photo, and press the "Submit Release" button. Congrats on appearing in <em>%{name}</em>. After scrolling down and reading the appearance release form, please enter your personal information, take a selfie photo and press the "Submit Release" button. If the person appearing on camera is a minor, you will enter their personal information first, select the button noting this person is a minor, and then enter your own personal info under "Guardian Information" at the bottom.
legal: legal:
heading: Legal heading: Legal
personal_info: personal_info:
heading: Personal Information heading: Personal Information
instructions: Now, enter your personal information. instructions: Enter the personal information for the person appearing on camera.
photo: photo:
camera_instructions_html: Click <em>Take Photo</em> to Turn ON Camera camera_instructions_html: Click <em>Take Photo</em> to Turn ON Camera
heading: Take a Photo heading: Photo of Person Appearing on Camera
instructions: > instructions: >
Lastly, it's time for you to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese! 'Before you take your selfie photo, remove your hat and sunglasses (regular eyewear is okay). Make sure you are the only person in the frame, look straight at the camera and snap the photo. NOTE: If you are a Guardian, you must take the photo of the minor. Minor photo is required only for record keeping purposes to maintain proof of parental consent and to identify minor within the Program.'
no_photo: No photo yet no_photo: No photo yet
take_photo: Take Photo take_photo: Take Photo
warning: If your photo appears sideways, it will be autocorrected when you submit your release. warning: If your photo appears sideways, it will be autocorrected when you submit your release.
signature: signature:
heading: Sign Below heading: Sign Below
broadcasts:
show:
alert: That broadcast is no longer available
location_releases: location_releases:
create: create:
notice: Your release has been signed. Thank you! notice: Your release has been signed. Thank you!
new: new:
cancel: Cancel cancel: Cancel
contact_info: contact_info:
heading: Signer Information heading: Owner Contact Information
filming_info: filming_info:
heading: Filming Information heading: Filming Information
legal: legal:
heading: Legal heading: Legal
location_info: location_info:
heading: Location Information heading: Location Information
photos:
heading: Photos
signature: signature:
heading: Sign Below heading: Sign Below
material_releases: material_releases:
@@ -797,13 +933,79 @@ en:
new: new:
cancel: Cancel cancel: Cancel
contact_info: contact_info:
heading: Signer's Contact Information heading: Licensor/Owner Contact Information
legal: legal:
heading: Legal heading: Legal
photo:
heading: Photos
release_info: release_info:
heading: Release Information heading: Release Information
signature: signature:
heading: Sign Below heading: Sign Below
medical_releases:
create:
notice: Your release has been signed. Thank you!
new:
cancel: Cancel
guardian_2_info:
heading: Second Guardian Information (if company requires)
guardian_2_photo:
heading: Second Guardian Photo
instructions: >
Lastly, it's time for second guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese!
guardian_clause:
heading: Guardian Clause
guardian_info:
heading: Guardian Information
guardian_photo:
heading: Guardian Photo
instructions: >
Lastly, it's time for guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese!
instructions_html: >
Below is the medical release form. After scrolling down and reading the medical release form, please enter your personal information, take a photo, and press the "Submit Release" button.
legal:
heading: Legal
personal_info:
heading: Personal Information
instructions: Now, enter your personal information.
photo:
camera_instructions_html: Click <em>Take Photo</em> to Turn ON Camera
heading: Photos
no_photo: No photo yet
take_photo: Take Photo
warning: If your photo appears sideways, it will be autocorrected when you submit your release.
questionnaire:
heading: Questionnaire
signature:
heading: Signature
misc_releases:
create:
notice: Your release has been signed. Thank you!
new:
cancel: Cancel
guardian_clause:
heading: Guardian Clause
guardian_info:
heading: Guardian Information
guardian_photo:
camera_instructions_html: Click <em>Take Photo</em> to Turn ON Camera
heading: Guardian Photo
instructions: >
Lastly, it's time for guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese!
no_photo: No photo yet
take_photo: Take Photo
warning: If your photo appears sideways, it will be autocorrected when you submit your release.
instructions_html: >
Below is the misc release form. After scrolling down and reading the misc release form, please enter your personal information, take a photo, and press the "Submit Release" button.
legal:
heading: Legal
personal_info:
heading: Personal Information
instructions: Now, enter your personal information.
photo:
heading: Photos
signature:
heading: Signature
talent_releases: talent_releases:
create: create:
notice: Your release has been signed. Thank you! notice: Your release has been signed. Thank you!
@@ -891,6 +1093,7 @@ en:
search: Search search: Search
submit_release: Submit Release submit_release: Submit Release
submit_release_long: I have read and agree to the above submit_release_long: I have read and agree to the above
submit_release_short: Submit
suite: Suite suite: Suite
tag_multiple_releases: Add Tag tag_multiple_releases: Add Tag
tag_multiple_releases_form: tag_multiple_releases_form:

View File

@@ -25,9 +25,16 @@ es:
appearance_releases: appearance_releases:
create: create:
failed_import: Failed to create appearance release for files listed below (ES) failed_import: Failed to create appearance release for files listed below (ES)
matching_started: Matching started (ES)
no_attachments: Failed to import - no attachments (ES) no_attachments: Failed to import - no attachments (ES)
form: form:
guardian_2_info:
heading: Second Guardian Information (if company requires) (ES)
guardian_info:
heading: Guardian Information (ES)
photos: photos:
guardian_2_photo:
heading: Second Guardian Photo (ES)
guardian_photo: guardian_photo:
heading: Guardian Photo (ES) heading: Guardian Photo (ES)
person_photo: person_photo:
@@ -37,6 +44,8 @@ es:
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
incomplete_match: Incomplete Match (ES)
matched_import: Complete Match (ES)
type_filter_actions: type_filter_actions:
all_releases: All Releases (ES) all_releases: All Releases (ES)
complete_releases: Complete Releases (ES) complete_releases: Complete Releases (ES)
@@ -52,8 +61,18 @@ es:
blank_contracts: blank_contracts:
create: create:
number_of_copies_invalid_notice: Please enter valid number greater than 0 (ES) number_of_copies_invalid_notice: Please enter valid number greater than 0 (ES)
form:
custom_fields:
heading: Medical Questionnaire (ES)
exploitable_rights:
heading: Exploitable Rights (ES)
legal:
heading: Legal (ES)
release_info:
heading: Release Info (ES)
contracts: contracts:
photos: photos:
guardian_2_photo_heading: Second guardian photo (ES)
guardian_photo_heading: Guardian photo (ES) guardian_photo_heading: Guardian photo (ES)
heading: heading:
one: Photo (ES) one: Photo (ES)
@@ -101,16 +120,73 @@ es:
errors_helper: errors_helper:
failure_message: "Los siguientes errores han impedido que se presente este %{model_name}:" failure_message: "Los siguientes errores han impedido que se presente este %{model_name}:"
helpers: helpers:
help:
contract_template:
fee: Leave at $0.00 for no-fee (ES)
guardian_clause: Leave blank if not required for this contract (ES)
label: label:
appearance_release: appearance_release:
guardian_address: Dirección del tutor legal guardian_2_address_city: Guardian 2 city (ES)
guardian_2_address_country: Guardian 2 country (ES)
guardian_2_address_state: Guardian 2 state (ES)
guardian_2_address_street1: Guardian 2 address (ES)
guardian_2_address_street2: Guardian 2 address (Line 2) (ES)
guardian_2_address_zip: Guardian 2 zip code (ES)
guardian_2_email: Guardian 2 email (ES)
guardian_2_first_name: Guardian 2 first name (ES)
guardian_2_last_name: Guardian 2 last name (ES)
guardian_2_phone: Guardian 2 phone (ES)
guardian_address_city: Guardian city (ES)
guardian_address_country: Guardian country (ES)
guardian_address_state: Guardian state (ES)
guardian_address_street1: Dirección del tutor legal
guardian_address_street2: Dirección del tutor legal (Línea 2)
guardian_address_zip: Guardian zip code (ES)
guardian_name: Nómbre del tutor legal guardian_name: Nómbre del tutor legal
guardian_phone: Número de teléfono del tutor legal guardian_phone: Número de teléfono del tutor legal
minor: El firmante es un menor minor: El firmante es un menor
person_address: Dirección person_address_city: City (ES)
person_address_country: Country (ES)
person_address_state: State (ES)
person_address_street1: Address (ES)
person_address_street2: Address (Line 2) (ES)
person_email: Dirección de correo electrónico person_email: Dirección de correo electrónico
person_name: Nómbre person_name: Nómbre
person_phone: Número de teléfono person_phone: Número de teléfono
medical_release:
guardian_2_address_city: Guardian 2 city (ES)
guardian_2_address_country: Guardian 2 country (ES)
guardian_2_address_state: Guardian 2 state (ES)
guardian_2_address_street1: Guardian 2 address (ES)
guardian_2_address_street2: Guardian 2 address (Line 2) (ES)
guardian_2_address_zip: Guardian 2 zip code (ES)
guardian_2_email: Guardian 2 email (ES)
guardian_2_first_name: ""
guardian_2_last_name: ""
guardian_2_phone: ""
guardian_address_city: Guardian City (ES)
guardian_address_country: Guardian country (ES)
guardian_address_state: Guardian State (ES)
guardian_address_street1: Guardian address (ES)
guardian_address_street2: Guardian address (line 2) (ES)
guardian_address_zip: Guardian ZIP (ES)
guardian_email: Guardian email (ES)
guardian_first_name: Guardian First name (ES)
guardian_last_name: Guardian Last name (ES)
guardian_phone: Guardian Phone (ES)
minor: El firmante es un menor
person_address_city: Person City (ES)
person_address_country: Country (ES)
person_address_state: Person State (ES)
person_address_street1: Person Address (ES)
person_address_street2: Person Address (line 2) (ES)
person_address_zip: Person ZIP (ES)
person_date_of_birth: Date of birth (ES)
person_email: Email address (ES)
person_first_name: First name (ES)
person_last_name: Last name (ES)
person_name: Name (ES)
person_phone: Phone number (ES)
project: project:
client_name: Nómbre del cliente del proyecto client_name: Nómbre del cliente del proyecto
description: Descripción del proyecto description: Descripción del proyecto
@@ -132,12 +208,26 @@ es:
update: Save Changes (ES) update: Save Changes (ES)
create: 'Crear %{model}' create: 'Crear %{model}'
update: 'Actualizar %{model}' update: 'Actualizar %{model}'
location_releases:
form:
photos:
dropzone_label: Tap to take a photo of the Property (optional) (ES)
material_releases:
form:
photos:
dropzone_label: Tap to take a photo of Licensed Material (optional) (ES)
public: public:
appearance_releases: appearance_releases:
create: create:
notice: La autorización está firmada. ¡Gracias! notice: La autorización está firmada. ¡Gracias!
new: new:
cancel: Cancelar cancel: Cancelar
guardian_2_info:
heading: Second Guardian Information (if company requires) (ES)
guardian_2_photo:
heading: Second Guardian Photo (ES)
instructions: >
(ES) Lastly, it's time for second guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese! (ES)
guardian_clause: guardian_clause:
heading: Guardian Clause (ES) heading: Guardian Clause (ES)
guardian_photo: guardian_photo:
@@ -160,6 +250,35 @@ es:
clear: Despejar clear: Despejar
heading: Firma heading: Firma
instructions: 'Firma Abajo:' instructions: 'Firma Abajo:'
location_releases:
new:
photos:
heading: Photos (ES)
material_releases:
new:
photo:
heading: Photos (ES)
medical_releases:
new:
guardian_2_info:
heading: Second Guardian Information (if company requires) (ES)
guardian_2_photo:
heading: Second Guardian Photo (ES)
instructions: >
(ES) Lastly, it's time for second guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese! (ES)
guardian_clause:
heading: Guardian Clause (ES)
guardian_info:
heading: Gurdian Information (ES)
guardian_photo:
heading: Guardian Photo (ES)
instructions: >
(ES) Lastly, it's time for guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese! (ES)
photo:
camera_instructions_html: Haga clic en <em>Take Photo</em> para encender la cámara
no_photo: No hay foto todavía
take_photo: Take Photo (ES)
warning: Si su foto aparece de lado, se corregirá automáticamente cuando actualizar la autorización
talent_releases: talent_releases:
new: new:
guardian_clause: guardian_clause:

View File

@@ -53,6 +53,8 @@ Rails.application.routes.draw do
resources :material_releases, except: [:show], concerns: [:contractable, :notable, :photoable] resources :material_releases, except: [:show], concerns: [:contractable, :notable, :photoable]
resources :music_releases, except: [:show], concerns: [:contractable, :notable] resources :music_releases, except: [:show], concerns: [:contractable, :notable]
resources :talent_releases, except: [:show], concerns: [:contractable, :notable, :photoable] resources :talent_releases, except: [:show], concerns: [:contractable, :notable, :photoable]
resources :medical_releases, except: [:show], concerns: [:contractable, :notable, :photoable]
resources :misc_releases, except: [:show], concerns: [:contractable, :notable, :photoable]
resources :contract_templates, only: [:index, :new, :create, :destroy] do resources :contract_templates, only: [:index, :new, :create, :destroy] do
resource :qr_codes, only: [:show], controller: "contract_templates/qr_codes" resource :qr_codes, only: [:show], controller: "contract_templates/qr_codes"
resource :blank_contracts, only: [:show, :new, :create], controller: "contract_templates/blank_contracts" resource :blank_contracts, only: [:show, :new, :create], controller: "contract_templates/blank_contracts"
@@ -117,6 +119,8 @@ Rails.application.routes.draw do
resources :acquired_media_releases, only: [:new, :create] resources :acquired_media_releases, only: [:new, :create]
resources :location_releases, only: [:new, :create] resources :location_releases, only: [:new, :create]
resources :material_releases, only: [:new, :create] resources :material_releases, only: [:new, :create]
resources :medical_releases, only: [:new, :create]
resources :misc_releases, only: [:new, :create]
end end
end end
end end
@@ -126,7 +130,7 @@ Rails.application.routes.draw do
end end
RELEASES = [:acquired_media_releases, :appearance_releases, :talent_releases, :material_releases, :location_releases] RELEASES = [:acquired_media_releases, :appearance_releases, :talent_releases, :material_releases, :location_releases]
ALL_RELEASES = RELEASES + [:music_releases] ALL_RELEASES = RELEASES + [:music_releases, :medical_releases, :misc_releases]
ALL_RELEASES.each do |release| ALL_RELEASES.each do |release|
resources release, only: [], concerns: :taggable resources release, only: [], concerns: :taggable
@@ -161,6 +165,7 @@ Rails.application.routes.draw do
resources :appearance_releases, only: [:show] do resources :appearance_releases, only: [:show] do
resources :notes, controller: "notes", only: [:create, :index] resources :notes, controller: "notes", only: [:create, :index]
end end
resources :direct_uploads, only: [:create]
end end
end end

View File

@@ -0,0 +1,7 @@
class AssignAccountNumberAndTypeToZoomUsers < ActiveRecord::DataMigration
def up
ZoomUser.find_each do |zu|
zu.update account_number: ENV.fetch('ZOOM_ACCOUNT_NUMBER'), tier: (ENV['ZOOM_USER_TYPE'] == 'pro' ? 1 : 0)
end
end
end

View File

@@ -0,0 +1,9 @@
class ChangeExistingZoomUserSettings < ActiveRecord::DataMigration
def up
gateway = ZoomGateway.new
ZoomUser.find_each do |zu|
gateway.update_user_settings zu.api_id
end
end
end

View File

@@ -0,0 +1,9 @@
class CreateMatchingRequests < ActiveRecord::Migration[6.0]
def change
create_table :matching_requests do |t|
t.belongs_to :project, foreign_key: true
t.timestamps
end
end
end

View File

@@ -0,0 +1,5 @@
class AddIdentifierToAppearanceReleases < ActiveRecord::Migration[6.0]
def change
add_column :appearance_releases, :identifier, :string, default: nil
end
end

View File

@@ -0,0 +1,6 @@
class AddAccountNumberAndTypeToZoomUsers < ActiveRecord::Migration[6.0]
def change
add_column :zoom_users, :account_number, :string
add_column :zoom_users, :tier, :integer, default: 0
end
end

View File

@@ -0,0 +1,5 @@
class AddFilmingHoursToLocationReleases < ActiveRecord::Migration[6.0]
def change
add_column :location_releases, :filming_hours, :text
end
end

Some files were not shown because too many files have changed in this diff Show More