Compare commits

...

6 Commits

Author SHA1 Message Date
bilal
b6cd775068 change submit button copy for medical release 2020-06-12 16:39:18 +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
98 changed files with 1815 additions and 334 deletions

View File

@@ -1,13 +1,8 @@
$(document).on "turbolinks:load", ->
# Only connect if a broadcast-token meta tag is present
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 },
subscribeToBroadcast = (broadcastToken) -> App.cable.subscriptions.create { channel: "BroadcastsChannel", token: broadcastToken },
connected: ->
# Called when the subscription is ready for use on the server
console.info "Subscribed to channel for broadcast:#{broadcastToken}"
disconnected: ->
# Called when the subscription has been terminated by the server
@@ -17,7 +12,7 @@ $(document).on "turbolinks:load", ->
switch data.event
when "broadcast_stream_update" then @refreshBroadcastVideo(data)
when "stream_recording_ready" then @showBroadcastRecordings(data)
when "file_upload_update" then @refreshFilesTab(data)
when "file_upload_update" then @refreshBroadcastFilesTab(data)
refreshBroadcastVideo: (data) ->
$("#broadcast_updates").html data.status_content
@@ -38,8 +33,12 @@ $(document).on "turbolinks:load", ->
$(".flash-message").html data.flash_content
$("#broadcast_recordings").html data.recordings_content
$("#broadcast_recordings_nav").html data.recordings_nav_content
refreshFilesTab: (data) ->
$("#broadcast_file_list").html data.files_content
$("#broadcast_files_pagination").html data.pagination_content
refreshBroadcastFilesTab: (data) ->
$("#broadcast_file_list_#{data.broadcast_token}").html data.files_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) {
const select = event.target;
const target = select.dataset.target;
const showValues = JSON.parse(select.dataset.showValues);
if (showValues.indexOf(select.value) > -1) {
$(target).show("fast");
} else {
$(target).hide("fast");
}
const mappings = JSON.parse(select.dataset.targetShowValuesMapping);
$.each(mappings, function( key, value ) {
if (value.indexOf(select.value) > -1) {
$(key).show("fast");
} else {
$(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) {
multi_view_ids = $.param({multi_view_ids: broadcast_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("target", "_blank");
$("#multi_view_broadcasts").removeClass('disabled');

View File

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

View File

@@ -35,11 +35,12 @@ class BroadcastsChannel < ApplicationCable::Channel
recordings_nav_content: recordings_nav_content
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
broadcast_to broadcast, {
event: :file_upload_update,
broadcast_token: broadcast.token,
files_content: files_content,
pagination_content: pagination_content
}

View File

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

View File

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

@@ -61,7 +61,12 @@ class ContractTemplatesController < ApplicationController
:applicable_medium_id, :applicable_medium_text,
:territory_id, :territory_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)
end
def download_attributes

View File

@@ -68,7 +68,8 @@ class LocationReleasesController < ApplicationController
:territory_id, :territory_text,
:term_id, :term_text,
:restriction_id, :restriction_text,
:filming_started_on, :filming_ended_on
:filming_started_on, :filming_ended_on,
:filming_hours
)
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

@@ -60,7 +60,7 @@ class ProjectsController < ApplicationController
end
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 video_analysis)
end
def project_params_with_current_account

View File

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

View File

@@ -6,8 +6,8 @@ class Public::BroadcastsController < Public::BaseController
@conference_url = broadcast_zoom_meeting_url(@broadcast.token)
@multi_view_broadcasts = multi_view_broadcasts
@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'
end
@@ -15,8 +15,8 @@ class Public::BroadcastsController < Public::BaseController
@broadcast.update(broadcast_params)
@files = @broadcast.files.order("created_at DESC").paginate(page: 1)
pagination_content = ApplicationController.render html: helpers.will_paginate(@files, params: { active_tab: params[:active_tab] })
BroadcastsChannel.file_upload_updates(@broadcast, @files, pagination_content)
pagination_content = ApplicationController.render html: helpers.will_paginate(@files,params: { active_tab: params[:active_tab], page: params[:page], active_files_tab: params[:active_files_tab] })
BroadcastsChannel.broadcast_file_upload_updates(@broadcast, @files, pagination_content)
end
private
@@ -29,7 +29,10 @@ class Public::BroadcastsController < Public::BaseController
Broadcast.
where(token: params[:multi_view_tokens]).
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
def set_broadcast
@@ -38,20 +41,29 @@ class Public::BroadcastsController < Public::BaseController
class MultiViewBroadcast
include Rails.application.routes.url_helpers
delegate_missing_to :@broadcast
def initialize(broadcast, multi_view_tokens)
def initialize(broadcast, multi_view_tokens, paginate_page)
@broadcast = broadcast
@multi_view_tokens = multi_view_tokens
@paginate_page = paginate_page
end
def url
broadcast_url(uid, multi_view_tokens: @multi_view_tokens, host: AppHost.new.domain_with_port, locale: I18n.locale)
end
def files
@broadcast.files.order("created_at DESC").paginate(page: @paginate_page)
end
def uid
token
end
def self.model_name
Broadcast.model_name
end
end
end

View File

@@ -63,7 +63,9 @@ class Public::LocationReleasesController < Public::BaseController
:person_address_zip,
:person_address_country,
:signature_base64,
:locale, :contract_template, :filming_started_on, :filming_ended_on
:locale, :contract_template, :filming_started_on, :filming_ended_on,
:filming_hours,
photos: []
)
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_address_street1, :person_address_street2, :person_address_city, :person_address_state, :person_address_zip, :person_address_country,
:signature_base64,
:locale, :contract_template, :description
:locale, :contract_template, :description, photos: []
)
end

View File

@@ -0,0 +1,86 @@
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,
: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,
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 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

@@ -5,7 +5,7 @@ class ZoomNotificationsController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :authorize_zoom
before_action :set_zoom_meeting, only: :create
before_action :set_zoom_meeting, only: [:create], if: :meeting_event?
def create
case notification_event
@@ -16,6 +16,12 @@ class ZoomNotificationsController < ApplicationController
when 'recording.completed'
recording = notification.dig(:payload, :object, :recording_files).first
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
Rails.logger.info notification_event
Rails.logger.info notification
@@ -42,6 +48,10 @@ class ZoomNotificationsController < ApplicationController
notification.dig(:payload, :object, :host_id)
end
def meeting_event?
notification_event.split(".").first.to_s.in? %w(meeting recording)
end
def set_zoom_meeting
@zoom_meeting = ZoomMeeting.find_by!(api_meeting_id: notification_meeting_id)
end

View File

@@ -3,8 +3,12 @@ module DropzoneHelper
case releasable.model_name.param_key
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"
when "material_release"
t 'material_releases.form.photos.dropzone_label'
when "music_release"
"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"
"To Add Files to the Folder:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files"
else

View File

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

View File

@@ -55,6 +55,7 @@ class Account < ApplicationRecord
User.joins(:project_memberships).where(project_memberships: { project: projects }),
Broadcast.where(project: projects),
ZoomMeeting.where(project: projects),
MedicalRelease.where(project: projects),
self
])).sum(:byte_size).to_f
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
]
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?
false

View File

@@ -13,6 +13,7 @@ class ContractTemplate < ApplicationRecord
has_many :acquired_media_releases, dependent: :restrict_with_error
has_many :location_releases, dependent: :restrict_with_error
has_many :material_releases, dependent: :restrict_with_error
has_many :medical_releases, dependent: :restrict_with_error
monetize :fee_cents
has_rich_text :body

View File

@@ -0,0 +1,71 @@
class MedicalRelease < ApplicationRecord
include Contractable
include Notable
include Photoable
include Releasable
include Searchable
include Signable
include Syncable
include PersonName
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 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 minor?
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 Syncable
SIGNABLE_RELEASE_TYPES = %w(talent appearance acquired_media location material)
AVAILABLE_RELEASE_TYPES = %w(appearance location material acquired_media talent music)
SIGNABLE_RELEASE_TYPES = %w(talent appearance acquired_media location material medical)
AVAILABLE_RELEASE_TYPES = %w(appearance location material acquired_media talent music medical)
belongs_to :account
has_many :acquired_media_releases, dependent: :destroy
@@ -13,6 +13,7 @@ class Project < ApplicationRecord
has_many :material_releases, dependent: :destroy
has_many :music_releases, dependent: :destroy
has_many :talent_releases, dependent: :destroy
has_many :medical_releases, dependent: :destroy
has_many :videos, dependent: :destroy
has_many :imports, dependent: :destroy
has_many :contract_templates, dependent: :destroy
@@ -33,6 +34,7 @@ class Project < ApplicationRecord
material_release: false,
music_release: false,
talent_release: false,
medical_release: false,
video_analysis: false,
}
end
@@ -65,6 +67,7 @@ class Project < ApplicationRecord
material_release: true,
music_release: true,
talent_release: true,
medical_release: true,
video_analysis: true,
}
when "nat_geo"
@@ -76,6 +79,7 @@ class Project < ApplicationRecord
material_release: true,
music_release: true,
talent_release: true,
medical_release: true,
video_analysis: true,
}
else
@@ -117,7 +121,7 @@ class Project < ApplicationRecord
current_zoom_meeting = zoom_meetings.active.first
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)
end

View File

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

View File

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

View File

@@ -1,19 +1,27 @@
require 'zoom_gateway'
require 'securerandom'
class ZoomUser < ApplicationRecord
has_many :zoom_meetings, dependent: :nullify
enum tier: [:basic, :pro]
after_create :create_api_user, if: -> { api_id.nil? }
before_destroy :abort_destroy
scope :current_account, -> { where(account_number: ZoomGateway.ACCOUNT_NUMBER) }
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
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
rescue ZoomGateway::UserAlreadyExists => e
retries += 1
if retries < 3
retry # new api email will be generated automatically
else
raise e
end
end
def delete_api_user
@@ -22,9 +30,22 @@ class ZoomUser < ApplicationRecord
save
end
def current_account?
account_number == ZoomGateway.ACCOUNT_NUMBER
end
# Static methods
class << self
def api_email(id)
"host#{id}@directme"
def generate_api_email
"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

View File

@@ -0,0 +1,37 @@
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_multiple?
true
end
end

View File

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

View File

@@ -1,4 +1,4 @@
<%= 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, 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") } %>
<% 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

@@ -5,6 +5,12 @@
<% if @broadcast %>
<meta name="broadcast-token" 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" content="<%= multi_view_broadcast.token %>">
<% end %>
<% end %>
<% end %>
<% content_for :header do %>
@@ -24,9 +30,7 @@
<div class="d-flex justify-content-between align-items-center">
<h1 class="h3 m-0"><%= @broadcast.name %></h1>
<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">
Switch View
</a>
<%= link_to "Switch View", "#", class: "btn btn-light border dropdown-toggle", role: "button", id: "dropdownMenuLink", data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } %>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<h5 class="dropdown-header">Live Streams</h5>
<span class="dropdown-item active"><%= fa_icon("check", text: @broadcast.name.titleize) %></span>
@@ -72,13 +76,10 @@
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<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 class="nav-item">
<a class="<%= class_string("nav-link", "active" => params[:active_tab] == "files") %>" href="#files" data-toggle="tab">Files</a>
</li>
<li class="nav-item">
<a class="<%= class_string("nav-link", "active" => params[:active_tab] == "recordings") %>" href="#recordings" data-toggle="tab">Previous Sessions</a>
<%= link_to "Previous Sessions", "#recordings", class: class_string("nav-link", "active" => params[:active_tab] == "recordings"), data: { toggle: "tab" } %>
</li>
</ul>
</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>
<%= link_to 'Video Conference', @conference_url, class: 'btn btn-primary btn-block', target: '_blank' %>
</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 id="broadcast_recordings">
<%= render partial: 'broadcasts/broadcast_recordings', locals: { recordings: @recordings, broadcast: @broadcast } %>
@@ -149,5 +127,36 @@
</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>

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) %>"
if ($("#broadcast_file_list").has(file_id).length == 0) {
$("#broadcast_file_list").html("<%= j render(partial: "broadcasts/file", collection: @files) %>");
$("#broadcast_files_pagination").html("<%= j will_paginate(@files) %>");
if ($("#broadcast_file_list_<%= @broadcast.token %>").has(file_id).length == 0) {
$("#broadcast_file_list_<%= @broadcast.token %>").html("<%= j render(partial: "broadcasts/file", collection: @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,20 +2,24 @@
<%= field_set_tag content_tag(:span, t(".release_info.heading"), class: "h6 text-muted text-uppercase") do %>
<div class="form-row">
<%= 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), "#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 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" %>
</div>
<% end %>
<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 %>
<hr>
<% end %>
<%= field_set_tag content_tag(:span, t(".custom_fields.heading"), class: "h6 text-muted text-uppercase"), id: "custom_fields", style: "display: none;" do %>
<%= render "shared/custom_fields", form: form %>
<hr>
<% end %>
<hr>
<%= field_set_tag content_tag(:span, t(".legal.heading"), class: "h6 text-muted text-uppercase") do %>
<%= form.form_group do %>

View File

@@ -29,6 +29,7 @@
<% if releasable.model_name == "LocationRelease" %>
<%= 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 Hours:", releasable&.filming_hours %>
<% end %>
<% if contract_template.fee? %>
<%= description_list_pair "Fee:", number_to_currency(contract_template.fee) %>
@@ -38,6 +39,15 @@
<% end %>
</dl>
<% if releasable.model_name == "MedicalRelease" %>
<% (1..10).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 %>
<% end %>
<% if releasable.minor? %>
<br/>
<p class="text-left"><strong>Guardian Information</strong></p>

View File

@@ -11,14 +11,10 @@
<%= field_set_tag content_tag(:span, t(".signer_details.heading"), class: "h6 text-muted text-uppercase") do %>
<div class="form-row">
<%= form.text_field :person_first_name, wrapper_class: "col-sm-3" %>
<%= form.text_field :person_last_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-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>
<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>
@@ -38,6 +34,7 @@
<div class="form-row">
<%= 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_hours, wrapper_class: "col-sm-12" %>
</div>
<% end %>

View File

@@ -13,14 +13,10 @@
<%= field_set_tag content_tag(:span, t(".signer_details.heading"), class: "h6 text-muted text-uppercase") do %>
<div class="form-row">
<%= form.text_field :person_first_name, wrapper_class: "col-sm-3" %>
<%= form.text_field :person_last_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-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>
<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>

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

@@ -1,6 +1,6 @@
<%= bootstrap_form_with model: project, local: true do |form| %>
<%= 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'%>">
<%= form.text_field :client_name, placeholder: true %>
<%= form.form_group do %>

View File

@@ -15,12 +15,12 @@
<%= card_field_set_tag t(".acquired_media_info.heading") do %>
<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 class="form-row">
<%= form.text_area :description, wrapper_class: "col-12" %>
</div>
<%= form.form_group :categories, label: { text: "Categories" } do %>
<%= form.form_group :categories, label: { text: "Licensed property type" } do %>
<% AcquiredMediaRelease::CATEGORIES.each do |category| %>
<%= form.check_box :categories, { multiple: true, label: category }, category, false %>
<% end %>
@@ -31,8 +31,11 @@
<%= card_field_set_tag t(".personal_info.heading") do %>
<div class="form-row">
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_phone, wrapper_class: "col-sm-6", label: 'Phone' %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6", label: 'Phone' %>
<%= form.email_field :person_email, wrapper_class: "col-sm-6", label: 'Email' %>
<%= form.text_field :person_fax, wrapper_class: "col-sm-6", label: 'Fax' %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>

View File

@@ -1,4 +1,4 @@
<%= 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, 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") } %>
<% 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) %>"
if ($("#broadcast_file_list").has(file_id).length == 0) {
$("#broadcast_file_list").html("<%= j render(partial: "broadcasts/file", collection: @files) %>");
$("#broadcast_files_pagination").html("<%= j will_paginate(@files) %>");
if ($("#broadcast_file_list_<%= @broadcast.token %>").has(file_id).length == 0) {
$("#broadcast_file_list_<%= @broadcast.token %>").html("<%= j render(partial: "broadcasts/file", collection: @files) %>");
$("#broadcast_files_pagination_<%= @broadcast.token %>").html("<%= j will_paginate(@files) %>");
}
bsCustomFileInput.init();

View File

@@ -27,11 +27,7 @@
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, 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>
<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>
@@ -45,9 +41,14 @@
<div class="form-row">
<%= 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_hours, wrapper_class: "col-sm-12" %>
</div>
<% 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 %>
<%= render "shared/signature_fields", form: form, instruction: 'An Authorized Signatory' %>
<% end %>

View File

@@ -27,17 +27,17 @@
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, 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>
<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 %>
<%= card_field_set_tag t(".photo.heading") do %>
<%= render "shared/photos_dropzone_fields", form: form, release: @material_release %>
<% end %>
<hr>
<%= card_field_set_tag t(".signature.heading") do %>

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,56 @@
<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>
<% if (1..10).map {|n| @contract_template.public_send("question_#{n}_text").presence }.compact.any? %>
<%= card_field_set_tag t(".questionnaire.heading") do %>
<% (1..10).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 %>
<%= 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

@@ -11,6 +11,6 @@
</div>
<%= form.form_group "#{field_name_prefix}address_country" do %>
<%= 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 %>

View File

@@ -0,0 +1,5 @@
<% (1..10).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_gateway'
unless Rails.env.test?
Zoom.configure do |c|
c.api_key = ENV['ZOOM_API_KEY']

View File

@@ -212,12 +212,14 @@ en:
archived_failure: Failed to archive the release template
archived_notice: The release template has been archived
form:
custom_fields:
heading: Custom Fields
exploitable_rights:
heading: 2 of 3 Exploitable Rights
heading: Exploitable Rights
legal:
heading: 3 of 3 Legal
heading: Legal
release_info:
heading: 1 of 3 Release Info
heading: Release Info
index:
actions:
import: Import Release Template
@@ -305,6 +307,8 @@ en:
graphics_only_edl_file: If you do not upload a Graphics Only EDL, the software will not generate a Graphics Cue List.
label:
acquired_media_release:
description: Description of licensed property
name: Name of licensed property
person_address: Address
person_address_city: City
person_address_country: Country
@@ -314,6 +318,8 @@ en:
person_address_zip: Zip code
person_company: Company
person_email: Email address
person_first_name: Licensor/Owner first name
person_last_name: Licensor/Owner last name
person_name: Name
person_phone: Phone number
person_title: Title
@@ -327,16 +333,23 @@ en:
address_city: City
address_country: Country
address_state: State
address_street1: Address
address_street1: Address of Property
address_street2: Address (Line 2)
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_country: Country
person_address_state: State
person_address_street1: Address
person_address_street2: Address (Line 2)
person_address_zip: Zip code
person_first_name: Owner first name
person_last_name: Owner last name
material_release:
description: Description of licensed material
name: Name of licensed material
person_address: Address
person_address_city: City
person_address_country: Country
@@ -346,6 +359,8 @@ en:
person_address_zip: Zip code
person_company: Company
person_email: Email address
person_first_name: Licensor/Owner first name
person_last_name: Licensor/Owner last name
person_name: Name
person_phone: Phone number
person_title: Title
@@ -542,9 +557,10 @@ en:
location_details:
heading: 1 of 4 Location Details
photos:
dropzone_label: Tap to take a photo of the Property (optional)
heading: 4 of 4 Photos
signer_details:
heading: 2 of 4 Signer Details
heading: 2 of 4 Owner Details
index:
actions:
new: Import Release
@@ -576,9 +592,10 @@ en:
material_details:
heading: 1 of 3 Material Details
photos:
dropzone_label: Tap to take a photo of Licensed Material (optional)
heading: 4 of 4 Photos
signer_details:
heading: 2 of 4 Signer Details
heading: 2 of 4 Licensor/Owner Details
index:
actions:
new: Import Release
@@ -596,6 +613,20 @@ en:
heading: Import Material Release (Products / Logos)
update:
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
music_releases:
create:
notice: The music release has been created
@@ -701,6 +732,7 @@ en:
label: Which release categories do you require for this project?
location_release: Location Releases
material_release: Material Releases (Products / Logos)
medical_release: Medical Releases
music_release: Music Releases (Original Music)
talent_release: Talent Releases
index:
@@ -727,6 +759,7 @@ en:
downloads: Downloads
location_release: Location Releases (%{count})
material_release: Material Releases (%{count})
medical_release: Medical Releases (%{count})
music_release: Music Releases (%{count})
report: Reports
talent_release: Talent Releases (%{count})
@@ -741,9 +774,7 @@ en:
legal:
heading: Legal
personal_info:
heading: Person Details
personal_info:
heading: Signer's Contact Information
heading: Licensor/Owner Contact Information
signature:
heading: Signature
appearance_releases:
@@ -782,13 +813,15 @@ en:
new:
cancel: Cancel
contact_info:
heading: Signer Information
heading: Owner Contact Information
filming_info:
heading: Filming Information
legal:
heading: Legal
location_info:
heading: Location Information
photos:
heading: Photos
signature:
heading: Sign Below
material_releases:
@@ -797,13 +830,33 @@ en:
new:
cancel: Cancel
contact_info:
heading: Signer's Contact Information
heading: Licensor/Owner Contact Information
legal:
heading: Legal
photo:
heading: Photos
release_info:
heading: Release Information
signature:
heading: Sign Below
medical_releases:
create:
notice: Your release has been signed. Thank you!
new:
cancel: Cancel
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:
heading: Photos
questionnaire:
heading: Questionnaire
signature:
heading: Signature
talent_releases:
create:
notice: Your release has been signed. Thank you!
@@ -891,6 +944,7 @@ en:
search: Search
submit_release: Submit Release
submit_release_long: I have read and agree to the above
submit_release_short: Submit
suite: Suite
tag_multiple_releases: Add Tag
tag_multiple_releases_form:

View File

@@ -132,6 +132,14 @@ es:
update: Save Changes (ES)
create: 'Crear %{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:
appearance_releases:
create:
@@ -160,6 +168,14 @@ es:
clear: Despejar
heading: Firma
instructions: 'Firma Abajo:'
location_releases:
new:
photos:
heading: Photos (ES)
material_releases:
new:
photo:
heading: Photos (ES)
talent_releases:
new:
guardian_clause:

View File

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

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

View File

@@ -0,0 +1,23 @@
class CreateMedicalReleases < ActiveRecord::Migration[6.0]
def change
create_table :medical_releases do |t|
t.belongs_to :project, foreign_key: true
t.belongs_to :contract_template, foreign_key: true
t.string :person_first_name
t.string :person_last_name
t.string :person_address_street1
t.string :person_address_street2
t.string :person_address_city
t.string :person_address_state
t.string :person_address_zip
t.string :person_address_country
t.string :person_phone
t.string :person_email
t.string :locale
t.text :notes
t.datetime :signed_at
t.timestamps
end
end
end

View File

@@ -0,0 +1,14 @@
class AddQuestionFieldsToContractTemplates < ActiveRecord::Migration[6.0]
def change
add_column :contract_templates, :question_1_text, :text
add_column :contract_templates, :question_2_text, :text
add_column :contract_templates, :question_3_text, :text
add_column :contract_templates, :question_4_text, :text
add_column :contract_templates, :question_5_text, :text
add_column :contract_templates, :question_6_text, :text
add_column :contract_templates, :question_7_text, :text
add_column :contract_templates, :question_8_text, :text
add_column :contract_templates, :question_9_text, :text
add_column :contract_templates, :question_10_text, :text
end
end

View File

@@ -0,0 +1,14 @@
class AddAnswerFieldsToMedicalReleases < ActiveRecord::Migration[6.0]
def change
add_column :medical_releases, :question_1_answer, :text
add_column :medical_releases, :question_2_answer, :text
add_column :medical_releases, :question_3_answer, :text
add_column :medical_releases, :question_4_answer, :text
add_column :medical_releases, :question_5_answer, :text
add_column :medical_releases, :question_6_answer, :text
add_column :medical_releases, :question_7_answer, :text
add_column :medical_releases, :question_8_answer, :text
add_column :medical_releases, :question_9_answer, :text
add_column :medical_releases, :question_10_answer, :text
end
end

View File

@@ -9,6 +9,20 @@ SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
--
CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
--
-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -
--
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
--
-- Name: fuzzystrmatch; Type: EXTENSION; Schema: -; Owner: -
--
@@ -50,7 +64,7 @@ $_$;
SET default_tablespace = '';
SET default_table_access_method = heap;
SET default_with_oids = false;
--
-- Name: account_auths; Type: TABLE; Schema: public; Owner: -
@@ -592,7 +606,17 @@ CREATE TABLE public.contract_templates (
term_text character varying,
restriction_id bigint,
restriction_text character varying,
archived_at timestamp without time zone
archived_at timestamp without time zone,
question_1_text text,
question_2_text text,
question_3_text text,
question_4_text text,
question_5_text text,
question_6_text text,
question_7_text text,
question_8_text text,
question_9_text text,
question_10_text text
);
@@ -615,15 +639,6 @@ CREATE SEQUENCE public.contract_templates_id_seq
ALTER SEQUENCE public.contract_templates_id_seq OWNED BY public.contract_templates.id;
--
-- Name: data_migrations; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.data_migrations (
version character varying NOT NULL
);
--
-- Name: directories; Type: TABLE; Schema: public; Owner: -
--
@@ -846,7 +861,8 @@ CREATE TABLE public.location_releases (
filming_started_on date,
filming_ended_on date,
person_first_name character varying,
person_last_name character varying
person_last_name character varying,
filming_hours text
);
@@ -927,6 +943,61 @@ CREATE SEQUENCE public.material_releases_id_seq
ALTER SEQUENCE public.material_releases_id_seq OWNED BY public.material_releases.id;
--
-- Name: medical_releases; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.medical_releases (
id bigint NOT NULL,
project_id bigint,
contract_template_id bigint,
person_first_name character varying,
person_last_name character varying,
person_address_street1 character varying,
person_address_street2 character varying,
person_address_city character varying,
person_address_state character varying,
person_address_zip character varying,
person_address_country character varying,
person_phone character varying,
person_email character varying,
locale character varying,
notes text,
signed_at timestamp without time zone,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
question_1_answer text,
question_2_answer text,
question_3_answer text,
question_4_answer text,
question_5_answer text,
question_6_answer text,
question_7_answer text,
question_8_answer text,
question_9_answer text,
question_10_answer text
);
--
-- Name: medical_releases_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.medical_releases_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: medical_releases_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.medical_releases_id_seq OWNED BY public.medical_releases.id;
--
-- Name: music_releases; Type: TABLE; Schema: public; Owner: -
--
@@ -1181,6 +1252,7 @@ CREATE TABLE public.settings (
--
CREATE SEQUENCE public.settings_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1216,6 +1288,7 @@ CREATE TABLE public.taggings (
--
CREATE SEQUENCE public.taggings_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1246,6 +1319,7 @@ CREATE TABLE public.tags (
--
CREATE SEQUENCE public.tags_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1592,7 +1666,9 @@ CREATE TABLE public.zoom_users (
id bigint NOT NULL,
api_id character varying,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
updated_at timestamp(6) without time zone NOT NULL,
account_number character varying,
tier integer DEFAULT 0
);
@@ -1762,6 +1838,13 @@ ALTER TABLE ONLY public.location_releases ALTER COLUMN id SET DEFAULT nextval('p
ALTER TABLE ONLY public.material_releases ALTER COLUMN id SET DEFAULT nextval('public.material_releases_id_seq'::regclass);
--
-- Name: medical_releases id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.medical_releases ALTER COLUMN id SET DEFAULT nextval('public.medical_releases_id_seq'::regclass);
--
-- Name: music_releases id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -2008,14 +2091,6 @@ ALTER TABLE ONLY public.contract_templates
ADD CONSTRAINT contract_templates_pkey PRIMARY KEY (id);
--
-- Name: data_migrations data_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.data_migrations
ADD CONSTRAINT data_migrations_pkey PRIMARY KEY (version);
--
-- Name: directories directories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2072,6 +2147,14 @@ ALTER TABLE ONLY public.material_releases
ADD CONSTRAINT material_releases_pkey PRIMARY KEY (id);
--
-- Name: medical_releases medical_releases_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.medical_releases
ADD CONSTRAINT medical_releases_pkey PRIMARY KEY (id);
--
-- Name: music_releases music_releases_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2567,6 +2650,20 @@ CREATE INDEX index_material_releases_on_term_id ON public.material_releases USIN
CREATE INDEX index_material_releases_on_territory_id ON public.material_releases USING btree (territory_id);
--
-- Name: index_medical_releases_on_contract_template_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_medical_releases_on_contract_template_id ON public.medical_releases USING btree (contract_template_id);
--
-- Name: index_medical_releases_on_project_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_medical_releases_on_project_id ON public.medical_releases USING btree (project_id);
--
-- Name: index_music_releases_on_applicable_medium_id; Type: INDEX; Schema: public; Owner: -
--
@@ -3003,6 +3100,14 @@ ALTER TABLE ONLY public.video_release_confirmations
ADD CONSTRAINT fk_rails_2787252ceb FOREIGN KEY (file_info_id) REFERENCES public.file_infos(id);
--
-- Name: medical_releases fk_rails_325442c794; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.medical_releases
ADD CONSTRAINT fk_rails_325442c794 FOREIGN KEY (contract_template_id) REFERENCES public.contract_templates(id);
--
-- Name: music_releases fk_rails_3a2b4033ad; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -3187,6 +3292,14 @@ ALTER TABLE ONLY public.zoom_meetings
ADD CONSTRAINT fk_rails_8d814ea729 FOREIGN KEY (broadcast_id) REFERENCES public.broadcasts(id);
--
-- Name: medical_releases fk_rails_98aa92daa9; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.medical_releases
ADD CONSTRAINT fk_rails_98aa92daa9 FOREIGN KEY (project_id) REFERENCES public.projects(id);
--
-- Name: contract_templates fk_rails_9b4d9d0e5a; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -3499,6 +3612,11 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200427073429'),
('20200428091105'),
('20200507110804'),
('20200512161738');
('20200512161738'),
('20200526113516'),
('20200603090419'),
('20200606044747'),
('20200610085411'),
('20200610140459');

View File

@@ -1,4 +1,3 @@
require 'zoom_gateway'
namespace :zoom do
desc "Setup necessary zoom roles and users"
task :setup => :environment do
@@ -17,4 +16,30 @@ namespace :zoom do
Rails.logger.info "Created role #{ZoomGateway.HOST_ROLE}."
end
end
desc "Synchronize ActiveRecord users with current account state"
task :sync => :environment do
zoom = Zoom.new
roles = zoom.roles_list["roles"]
ActiveRecord::Base.transaction do
ZoomUser.tiers.keys.each do |tier|
full_role_name = ZoomGateway.host_role_name(tier)
role_id = roles.select { |r| r["name"] == full_role_name }.first["id"]
user_ids = zoom.roles_members(role_id: role_id).dig("members").pluck("id")
# Invalid db users (not existing on the given Zoom account, but existing in the app db)
ZoomUser.current_account.public_send(tier).where.not(api_id: user_ids).each do |zu|
zu.api_id = nil
zu.destroy
end
# Missing zoom users (existing in given Zoom account, but not existing in the app db)
(user_ids - ZoomUser.current_account.public_send(tier).pluck(:api_id)).each do |api_user_id|
ZoomUser.current_account.public_send(tier).create(api_id: api_user_id)
end
end
end
end
end

View File

@@ -3,6 +3,7 @@ class ZoomGateway
class MeetingExpired < StandardError; end
class UserNotFound < StandardError; end
class TooManyHosts < StandardError; end
class UserAlreadyExists < StandardError; end
class << self
def USER_TYPE_NAME
@@ -20,16 +21,24 @@ class ZoomGateway
end
def HOST_ROLE
"#{self.USER_TYPE_NAME}-directme-host"
self.host_role_name(self.USER_TYPE_NAME)
end
def ACCOUNT_NUMBER
ENV['ZOOM_ACCOUNT_NUMBER']
end
def enable_recordings?
ENV['ZOOM_ENABLE_RECORDINGS'] == '1'
ENV['ZOOM_ENABLE_RECORDINGS'] == 'true'
end
def apply_limits?
self.USER_TYPE_NAME == 'pro'
end
def host_role_name(user_type_name)
"#{user_type_name}-directme-host"
end
end
def initialize
@@ -97,6 +106,8 @@ class ZoomGateway
raise UserNotFound, error.message
elsif error.status_code == 3001
raise MeetingExpired, error.message
elsif error.status_code == 1005
raise UserAlreadyExists, error.message
else
raise error
end

View File

@@ -50,4 +50,21 @@ RSpec.describe BroadcastsChannel, type: :channel do
})
end
end
describe ".broadcast_file_upload_updates" do
it 'broadcasts to the channel with the right data' do
broadcast = create(:broadcast, :with_stream, :with_files, skip_create_callback: true)
files_content = ApplicationController.render partial: "broadcasts/file", collection: broadcast.files
expect {
BroadcastsChannel.broadcast_file_upload_updates(broadcast, broadcast.files, "pagination_content")
}.to have_broadcasted_to(broadcast).with({
event: 'file_upload_update',
broadcast_token: broadcast.token,
files_content: files_content,
pagination_content: "pagination_content"
})
end
end
end

View File

@@ -111,17 +111,6 @@ RSpec.describe BroadcastsController, type: :controller do
end
end
describe "#update" do
let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, project: project ) }
it "uploads files to broadcast" do
patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true
expect(broadcast.files.count).to eq(1)
expect(broadcast.files.first.filename).to eq("contract.pdf")
end
end
describe "#show" do
let(:broadcast) { create(:broadcast, project: project, name: "Another Broadcast") }
@@ -198,6 +187,25 @@ RSpec.describe BroadcastsController, type: :controller do
end
end
describe "#update" do
let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, project: project ) }
it "uploads files to broadcast" do
patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true
expect(broadcast.files.count).to eq(1)
expect(broadcast.files.first.filename).to eq("contract.pdf")
end
it "sends an update to the broadcasts channel" do
allow(BroadcastsChannel).to receive(:broadcast_file_upload_updates)
patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true
expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates)
end
end
describe "#destroy" do
let!(:broadcast_2) { create(:broadcast, :with_stream, skip_create_callback: true, project: project, name: "Another Broadcast") }

View File

@@ -0,0 +1,91 @@
require "rails_helper"
RSpec.describe MedicalReleasesController, type: :controller do
render_views
let(:user) { create(:user) }
let(:account) { user.primary_account }
let(:project) { create(:project, account: user.primary_account) }
before do
sign_in user
end
describe "#index" do
it "responds successfully" do
get :index, params: { project_id: project }
expect(response).to be_successful
end
it "renders content" do
release = create(:medical_release, project: project,
person_first_name: "My",
person_last_name: "Release",
person_phone: "5551234567",
person_email: "jane.doe@test.com")
create(:note, notable: release, content: "Some notes here")
get :index, params: { project_id: project }
expect(response.body).to have_content "My Release"
expect(response.body).to have_content "Some notes here"
expect(response.body).to have_content "Manage"
end
context "when there are no medical releases" do
it "renders an empty message" do
get :index, params: { project_id: project }
expect(response.body).to have_content("Medical releases will appear here")
end
end
context "when there are many records" do
it "paginates the table" do
create_list(:medical_release, 20, project: project)
get :index, params: { project_id: project }
expect(response.body).to have_link("2", href: project_medical_releases_path(project, page: 2))
end
end
context "for xhr request" do
it "filters the releases by a query param" do
medical_releases = [
create(:medical_release, person_name: "Adam Sandler", project: project),
create(:medical_release, person_name: "Zoe Perry", project: project),
]
get :index, params: { project_id: project, query: "Zoe" }, xhr: true
expect(response.body).not_to have_content("Adam Sandler")
expect(response.body).to have_content("Zoe Perry")
end
end
end
describe "#destroy" do
let!(:medical_release) { create(:medical_release, project: project) }
it "responds with redirect" do
delete :destroy, params: { project_id: project, id: medical_release }
expect(response).to be_redirect
expect(response).to redirect_to [project, :medical_releases]
end
it "sets the flash" do
delete :destroy, params: { project_id: project, id: medical_release }
expect(flash.alert).not_to be_nil
end
it "destroys the record" do
expect {
delete :destroy, params: { project_id: project, id: medical_release }
}.to change(MedicalRelease, :count).by(-1)
end
end
end

View File

@@ -92,6 +92,14 @@ RSpec.describe Public::BroadcastsController, type: :controller do
expect(broadcast.files.count).to eq(1)
expect(broadcast.files.first.filename).to eq("contract.pdf")
end
it "sends an update to the broadcasts channel" do
allow(BroadcastsChannel).to receive(:broadcast_file_upload_updates)
patch :update, params: { token: broadcast.token, broadcast: file_params }, xhr: true
expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates)
end
end
after do

View File

@@ -7,6 +7,15 @@ describe Public::LocationReleasesController do
render_views
describe "#create" do
it "allows photos param" do
contract_template = create(:contract_template, project: project)
post :create, params: { account_id: user.primary_account.to_param, project_id: project, contract_template_id: contract_template, location_release: location_release_params_with_photos }
expect(response).to be_successful
expect(LocationRelease.last.photos.attached?).to eq true
end
it "logs analytics" do
contract_template = create(:contract_template, project: project)
@@ -67,6 +76,10 @@ describe Public::LocationReleasesController do
attributes_for(:location_release, :native).except(:signature).merge(signature_param).merge(person_address_params)
end
def location_release_params_with_photos
attributes_for(:location_release, :native, :with_photo).except(:signature).merge(signature_param)
end
def person_address_params
{
person_address_street1: "123 Broadway",

View File

@@ -7,6 +7,15 @@ describe Public::MaterialReleasesController do
render_views
describe "#create" do
it "allows photos param" do
contract_template = create(:contract_template, project: project)
post :create, params: { account_id: user.primary_account.to_param, project_id: project, contract_template_id: contract_template, material_release: material_release_params_with_photos }
expect(response).to be_successful
expect(MaterialRelease.last.photos.attached?).to eq true
end
it "logs analytics" do
contract_template = create(:contract_template, project: project)
@@ -65,6 +74,11 @@ describe Public::MaterialReleasesController do
attributes_for(:material_release, :native).except(:signature).merge(signature_param)
end
def material_release_params_with_photos
attributes_for(:material_release, :native, :with_photo).except(:signature).merge(signature_param)
end
def signature_param
file = file_fixture("signature.png")
data_uri = Base64Image.from_image(file).data_uri

View File

@@ -0,0 +1,71 @@
require "rails_helper"
RSpec.describe Public::MedicalReleasesController, type: :controller do
let(:user) { create(:user) }
let(:project) { create(:project, account: user.primary_account) }
render_views
describe "#create" do
it "logs analytics" do
contract_template = create(:contract_template, project: project)
expect {
post :create, params: { account_id: project.account.to_param, project_id: project, contract_template_id: contract_template, medical_release: medical_release_params }
}.to(
have_enqueued_job(TrackAnalyticsJob)
.with(nil, nil, :track_create_native_release, release_type: "MedicalRelease", account: project.account, user_agent: "Rails Testing", user_ip: "0.0.0.0")
)
end
it "displays validation errors" do
contract_template = create(:contract_template, project: project)
sign_in(user)
post :create, params: { account_id: user.primary_account.to_param, project_id: project, contract_template_id: contract_template, medical_release: { person_address_city: "Albuquerque" } }
body = CGI.unescape_html(response.body)
expect(body).to match /Person first name can't be blank/
expect(body).to match /Person last name can't be blank/
expect(body).to match />can't be blank</
end
it "responds with success " do
contract_template = create(:contract_template, project: project)
post :create, params: { account_id: user.primary_account.to_param, project_id: project, contract_template_id: contract_template, medical_release: medical_release_params }
expect(response).to be_successful
end
it "runs attach contract to releasable job" do
contract_template = create(:contract_template, project: project)
expect {
post :create, params: { account_id: project.account.to_param, project_id: project, contract_template_id: contract_template, medical_release: medical_release_params }
}.to(
have_enqueued_job(AttachContractToReleasableJob)
.with(MedicalRelease.last)
)
end
end
private
def medical_release_params
attributes_for(:medical_release, :native).except(:signature).merge(signature_param, photos_param)
end
def photos_param
path = Rails.root.join("spec", "fixtures", "files", "person_photo.png")
photo = Rack::Test::UploadedFile.new(path, "image/png")
{ photos: [photo] }
end
def signature_param
file = file_fixture("signature.png")
data_uri = Base64Image.from_image(file).data_uri
{ signature_base64: data_uri }
end
end

View File

@@ -1,5 +1,4 @@
require 'rails_helper'
require 'zoom_gateway'
RSpec.describe Public::ZoomMeetingsController, type: :controller do
let(:user) { create(:user) }

View File

@@ -1,5 +1,4 @@
require 'rails_helper'
require 'zoom_gateway'
RSpec.describe ZoomMeetingsController, type: :controller do
let(:user) { create(:user) }

View File

@@ -1,82 +0,0 @@
require "rails_helper"
RSpec.describe ZoomNotificationsController, type: :controller do
render_views
let!(:zoom_meeting) { create(:zoom_meeting, api_meeting_id: 'meeting_id') }
let(:started_status) { {event: 'meeting.started', payload: {object: {id: 'meeting_id' }}} }
let(:ended_status) { {event: 'meeting.ended', payload: {object: {id: 'meeting_id' }}} }
let(:wrong_meeting_id) { {payload: {object: {id: 'wrong_id' }}} }
let(:authorization_header) { {'Authorization' => 'xxx-xxx-xxx'} }
let(:wrong_authorization_header) { {'Authorization' => 'yyy-yyy-yyy'} }
before do
allow(ENV).to receive(:[]).with('ZOOM_VERIFICATION_TOKEN').and_return('xxx-xxx-xxx')
end
describe '#create' do
context 'with no authorization key' do
it 'raises 403 response' do
post :create, params: started_status
expect(response).to have_http_status(403)
end
end
context 'with wrong authorization key' do
it 'raises 403 response' do
request.headers.merge!(wrong_authorization_header)
post :create, params: started_status
expect(response).to have_http_status(403)
end
end
context 'authorized' do
before do
request.headers.merge!(authorization_header)
end
context 'with wrong meeting id' do
it 'raises RecordNotFound' do
expect {
post :create, params: wrong_meeting_id
}.to raise_error(ActiveRecord::RecordNotFound)
end
end
context 'with right meeting id' do
it 'responds with 200' do
post :create, params: started_status
expect(response).to have_http_status(200)
end
it 'assigns the zoom meeting' do
post :create, params: started_status
expect(assigns(:zoom_meeting)).to eq(zoom_meeting)
end
it 'updates the zoom_meeting when started status is received in notification' do
post :create, params: started_status
expect(zoom_meeting.reload).to be_started
end
it 'updates the zoom_meeting when ended status is received in notification' do
post :create, params: ended_status
expect(zoom_meeting.reload).to be_ended
end
it 'updates the recording when recording complete notification is received' do
expect {
post :create, params: recording_complete
}.to change { zoom_meeting.recording }
end
end
end
end
end

View File

@@ -0,0 +1,101 @@
require "rails_helper"
RSpec.describe ZoomNotificationsController, type: :controller do
render_views
let!(:zoom_meeting) { create(:zoom_meeting, api_meeting_id: 'meeting_id') }
let(:started_status) { {event: 'meeting.started', payload: {object: {id: 'meeting_id' }}} }
let(:ended_status) { {event: 'meeting.ended', payload: {object: {id: 'meeting_id' }}} }
let(:wrong_meeting_id) { {event: 'meeting.started', payload: {object: {id: 'wrong_id' }}} }
let(:recording_complete) { {event: 'recording.completed', payload: {object: {id: 'meeting_id', recording_files: [Object.new]}}} }
let(:authorization_header) { {'Authorization' => 'xxx-xxx-xxx'} }
let(:wrong_authorization_header) { {'Authorization' => 'yyy-yyy-yyy'} }
before do
allow(ENV).to receive(:[]).with('ZOOM_VERIFICATION_TOKEN').and_return('xxx-xxx-xxx')
end
describe '#create' do
context 'with no authorization key' do
it 'raises 403 response' do
post :create, params: started_status
expect(response).to have_http_status(403)
end
end
context 'with wrong authorization key' do
it 'raises 403 response' do
request.headers.merge!(wrong_authorization_header)
post :create, params: started_status
expect(response).to have_http_status(403)
end
end
context 'authorized' do
before do
request.headers.merge!(authorization_header)
end
context 'user hooks' do
before(:each) { ZoomUser.create api_id: 'zoom_user_id' }
it 'deletes the user from db if user.deleted is passed with existing user id' do
expect {
post :create, params: {event: 'user.deleted', payload: {object: {id: 'zoom_user_id'}}}
}.to change { ZoomUser.count }.by(-1)
end
it 'does not do anything if user.deleted is passed with non-existing user' do
expect {
post :create, params: {event: 'user.deleted', payload: {object: {id: 'wrong-user-id'}}}
}.not_to change { ZoomUser.count }
end
end
context 'meeting hooks' do
context 'with wrong meeting id' do
it 'raises RecordNotFound' do
expect {
post :create, params: wrong_meeting_id
}.to raise_error(ActiveRecord::RecordNotFound)
end
end
context 'with right meeting id' do
it 'responds with 200' do
post :create, params: started_status
expect(response).to have_http_status(200)
end
it 'assigns the zoom meeting' do
post :create, params: started_status
expect(assigns(:zoom_meeting)).to eq(zoom_meeting)
end
it 'updates the zoom_meeting when started status is received in notification' do
post :create, params: started_status
expect(zoom_meeting.reload).to be_started
end
it 'updates the zoom_meeting when ended status is received in notification' do
post :create, params: ended_status
expect(zoom_meeting.reload).to be_ended
end
it 'updates the recording when recording complete notification is received' do
expect(AttachRecordingToZoomMeetingJob).to receive(:perform_later)
post :create, params: recording_complete
end
end
end
end
end
end

View File

@@ -16,6 +16,10 @@ FactoryBot.define do
release_type "talent"
end
factory :medical_release_contract_template do
release_type "medical"
end
factory :material_release_contract_template do
release_type "material"
end

View File

@@ -15,6 +15,13 @@ FactoryBot.define do
end
end
trait :with_photo do
photos do
path = Rails.root.join("spec", "fixtures", "files", "location_photo.png")
[Rack::Test::UploadedFile.new(path, "image/png")]
end
end
trait :non_native do
contract do
path = Rails.root.join("spec", "fixtures", "files", "contract.pdf")

View File

@@ -15,6 +15,14 @@ FactoryBot.define do
end
end
trait :with_photo do
photos do
path = Rails.root.join("spec", "fixtures", "files", "material_photo.png")
[Rack::Test::UploadedFile.new(path, "image/png")]
end
end
trait :non_native do
contract do
path = Rails.root.join("spec", "fixtures", "files", "contract.pdf")

View File

@@ -0,0 +1,47 @@
FactoryBot.define do
factory :medical_release do
association :project
person_first_name "Jane"
person_last_name "Doe"
photos [Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "person_photo.png"), "image/png")]
trait :native do
person_phone "123-555-6789"
signature do
path = Rails.root.join("spec", "fixtures", "files", "signature.png")
Rack::Test::UploadedFile.new(path, "image/png")
end
end
trait :non_native do
contract do
path = Rails.root.join("spec", "fixtures", "files", "contract.pdf")
Rack::Test::UploadedFile.new(path, "application/pdf")
end
end
factory :medical_release_with_contract_template do
after(:build) do |medical_release, _|
medical_release.contract_template = build(:medical_release_contract_template)
end
end
factory :medical_release_with_contract_template_and_photos do
after(:build) do |medical_release, _|
medical_release.contract_template = build(:medical_release_contract_template)
path = Rails.root.join("spec", "fixtures", "files", "person_photo.png")
medical_release.photos.attach Rack::Test::UploadedFile.new(path, "image/png")
end
end
factory :medical_release_with_photo do
after(:build) do |medical_release, _|
path = Rails.root.join("spec", "fixtures", "files", "person_photo.png")
medical_release.photos.attach Rack::Test::UploadedFile.new(path, "image/png")
end
end
end
end

View File

@@ -1,5 +1,8 @@
FactoryBot.define do
factory :zoom_user do
account_number ZoomGateway.ACCOUNT_NUMBER
trait ZoomGateway.USER_TYPE_NAME
trait :with_api_id do
api_id "api_user_id"
end

View File

@@ -103,4 +103,10 @@ feature "User creates notes" do
it_behaves_like "a notable collection UI"
end
context "for medical releases" do
subject! { create(:medical_release, project: project, notes: []) }
it_behaves_like "a notable collection UI"
end
end

View File

@@ -86,4 +86,10 @@ feature "User creates tags" do
it_behaves_like "a taggable collection UI"
end
context "for medical releases" do
subject! { create(:medical_release, project: project, tags: []) }
it_behaves_like "a taggable collection UI"
end
end

View File

@@ -5,6 +5,13 @@ feature "User managing acquired_media releases" do
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
context "when signed out" do
scenario "United States is default country" do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_acquired_media_release_path(project.account, project, contract_template)
expect(country_field_value).to eq "US"
end
scenario "creating a release", js: true do
contract_template = create(:contract_template, project: project)
@@ -19,7 +26,7 @@ feature "User managing acquired_media releases" do
click_button "I have read and agree to the above"
expect(AcquiredMediaRelease.last.categories).to include("Artwork")
expect(AcquiredMediaRelease.last.categories).to include("Video Footage")
expect(AcquiredMediaRelease.last.categories).to include("Still Photograph")
expect(page).to have_content("Your release was successfully submitted. Thank you.")
end
@@ -205,12 +212,16 @@ feature "User managing acquired_media releases" do
private
def country_field_value
find_field("acquired_media_release[person_address_country]").value
end
def acquired_media_name_field
"acquired_media_release[name]"
end
def acquired_media_category_fields
find(:css, "#acquired_media_release_categories_artwork").set(true)
find(:css, "#acquired_media_release_categories_video_footage").set(true)
find(:css, "#acquired_media_release_categories_still_photograph").set(true)
end

View File

@@ -46,15 +46,17 @@ feature "User managing broadcasts" do
expect(page).to have_content("Live stream is waiting to begin.")
expect(page).to have_content("Copy URL")
click_on "Files"
expect(page).to have_content("contract.pdf")
within "#files" do
expect(page).to have_content("contract.pdf")
end
click_on "Previous Sessions"
expect(page).to have_content(recording.download_file_name)
end
scenario "visit multi-view broadcast page", js: true do
broadcasts = create_list(:broadcast, 4, :with_stream, project: project)
broadcast_one = create(:broadcast, :with_stream, :with_files, name: "Broadcast 1", project: project)
broadcast_two = create(:broadcast, :with_stream, :with_files, name: "Broadcast 2", project: project)
visit project_broadcasts_path(project)
click_checkboxes
@@ -64,8 +66,16 @@ feature "User managing broadcasts" do
expect(page).to have_content("Switch View")
click_on "Switch View"
expect(page).to have_link(broadcasts.first.name)
expect(page).to have_link(broadcasts.second.name)
expect(page).to have_link("Broadcast 1")
expect(page).to have_link("Broadcast 2")
within "#files" do
click_on "Broadcast 1"
expect(page).to have_content("contract.pdf")
click_on "Broadcast 2"
expect(page).to have_content("contract.pdf")
end
end
end
end
@@ -77,7 +87,7 @@ feature "User managing broadcasts" do
end
def click_checkboxes
all('input[type="checkbox"]')[0].click
all('input[type="checkbox"]')[1].click
all('input[type="checkbox"]')[2].click
end
end

View File

@@ -5,7 +5,14 @@ feature "User managing location releases" do
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
context "when signed out" do
scenario "creating a release", js: true do
scenario "United States is default country" do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_location_release_path(project.account, project, contract_template)
expect(country_field_value).to eq "US"
end
scenario "creating a release without photos", js: true do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_location_release_path(project.account, project, contract_template)
@@ -17,13 +24,35 @@ feature "User managing location releases" do
fill_in person_phone_field, with: "555-555-5555"
fill_in person_email_field, with: "jane.doe@test.com"
fill_in person_address_street1_field, with: "100 Broadway"
fill_in filming_hours_field, with: "04:00 - 22:00"
draw_signature file_fixture("signature.png"), "location_release_signature_base64"
end
click_button "I have read and agree to the above"
click_button submit_release_button
expect(page).to have_content("Your release was successfully submitted. Thank you.")
end
scenario "creating a release with photos", js: true do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_location_release_path(project.account, project, contract_template)
fill_in location_name_field, with: "Benny's Burritos"
fill_in person_first_name_field, with: "Jane"
fill_in person_last_name_field, with: "Doe"
fill_in person_phone_field, with: "555-555-5555"
fill_in person_email_field, with: "jane.doe@test.com"
fill_in person_address_street1_field, with: "100 Broadway"
fill_in filming_hours_field, with: "04:00 - 22:00"
draw_signature file_fixture("signature.png"), "location_release_signature_base64"
drop_file Rails.root.join(file_fixture("location_photo.png")), type: :dropzone
click_button submit_release_button
expect(page).to have_content("Your release was successfully submitted. Thank you.")
expect(LocationRelease.last.photos.attached?).to eq true
end
end
context "when signed in" do
@@ -51,6 +80,7 @@ feature "User managing location releases" do
by "filling out the remaining information" do
fill_in_release_fields name: "Test Location Release"
fill_in filming_hours_field, with: "04:00 - 22:00"
click_button create_release_button
expect(page).to have_content(create_release_notice)
expect(page).to have_photo("location_photo.png")
@@ -136,6 +166,7 @@ feature "User managing location releases" do
:native,
project: project,
name: "Benny's Burritos",
filming_hours: "06:00 - 20:00",
tag_list: "Restaurant",
notes: [
build(:note,
@@ -172,6 +203,8 @@ feature "User managing location releases" do
expect(pdf_body).to have_content("Restaurant")
expect(pdf_body).to have_content photos_heading.upcase
expect(pdf_body).to have_content("location_photo.png")
expect(pdf_body).to have_content("Filming Hours")
expect(pdf_body).to have_content("06:00 - 20:00")
end
context "when the user is associate" do
@@ -190,6 +223,10 @@ feature "User managing location releases" do
private
def country_field_value
find_field("location_release[person_address_country]").value
end
def photos_heading(photos_count = 1)
t 'contracts.photos.heading', count: photos_count
end
@@ -222,6 +259,10 @@ feature "User managing location releases" do
"location_release[person_phone]"
end
def filming_hours_field
"location_release[filming_hours]"
end
def have_photo(filename, attr: "src")
have_selector("img[#{attr}*='#{filename}']")
end
@@ -246,6 +287,10 @@ feature "User managing location releases" do
t "helpers.submit.location_release.create"
end
def submit_release_button
t("shared.submit_release_long")
end
def create_release_notice
t "location_releases.create.notice"
end

View File

@@ -5,7 +5,14 @@ feature "User managing material releases" do
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
context "when signed out" do
scenario "creating a release", js: true do
scenario "United States is default country" do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_material_release_path(project.account, project, contract_template)
expect(country_field_value).to eq "US"
end
scenario "creating a release without photos", js: true do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_material_release_path(project.account, project, contract_template)
@@ -17,10 +24,27 @@ feature "User managing material releases" do
draw_signature file_fixture("signature.png"), "material_release_signature_base64"
end
click_button "I have read and agree to the above"
click_button submit_release_button
expect(page).to have_content("Your release was successfully submitted. Thank you.")
end
scenario "creating a release with photos", js: true do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_material_release_path(project.account, project, contract_template)
fill_in material_name_field, with: "Pepsi Logo"
fill_in person_first_name_field, with: "Jane"
fill_in person_last_name_field, with: "Doe"
draw_signature file_fixture("signature.png"), "material_release_signature_base64"
drop_file Rails.root.join(file_fixture("material_photo.png")), type: :dropzone
click_button submit_release_button
expect(page).to have_content("Your release was successfully submitted. Thank you.")
expect(MaterialRelease.last.photos.attached?).to eq true
end
end
context "when signed in" do
@@ -180,6 +204,10 @@ feature "User managing material releases" do
private
def country_field_value
find_field("material_release[person_address_country]").value
end
def photos_heading(photos_count = 1)
t 'contracts.photos.heading', count: photos_count
end
@@ -224,6 +252,10 @@ feature "User managing material releases" do
t "helpers.submit.material_release.create"
end
def submit_release_button
t 'shared.submit_release_long'
end
def create_release_notice
t "material_releases.create.notice"
end

View File

@@ -5,6 +5,13 @@ feature "User managing talent releases" do
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
context "when signed out" do
scenario "United States is default country" do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_talent_release_path(project.account, project, contract_template)
expect(country_field_value).to eq "US"
end
scenario "creating a release for an adult", js: true do
contract_template = create(:contract_template, project: project)
@@ -274,6 +281,10 @@ feature "User managing talent releases" do
private
def country_field_value
find_field("talent_release[person_address_country]").value
end
def photos_heading(photos_count = 1)
t 'contracts.photos.heading', count: photos_count
end

View File

@@ -521,8 +521,8 @@ feature "User performs video analysis" do
new_path = polymorphic_path([:new, video, release, :video_release_confirmation])
first("form[action='#{new_path}']").click_button
expect(page).to have_content "Timecode in"
expect(page).to have_content "Source file name"
expect(page).to have_content "Timecode In"
expect(page).to have_content "Source File Name"
click_on "Show/Hide EDL Events"
within "#edl_events" do
@@ -572,8 +572,8 @@ feature "User performs video analysis" do
new_path = polymorphic_path([:new, video, release, :video_release_confirmation])
first("form[action='#{new_path}']").click_button
expect(page).to have_content "Timecode in"
expect(page).to have_content "Source file name"
expect(page).to have_content "Timecode In"
expect(page).to have_content "Source File Name"
click_on "Show/Hide EDL Events"
within "#edl_events" do
@@ -748,8 +748,8 @@ feature "User performs video analysis" do
open_graphics_element_modal(video)
expect(page).to have_content "Timecode in"
expect(page).to have_content "Source file name"
expect(page).to have_content "Timecode In"
expect(page).to have_content "Source File Name"
click_on "Show/Hide EDL Events"
within "#edl_events" do
@@ -796,8 +796,8 @@ feature "User performs video analysis" do
open_graphics_element_modal(video)
expect(page).to have_content "Timecode in"
expect(page).to have_content "Source file name"
expect(page).to have_content "Timecode In"
expect(page).to have_content "Source File Name"
click_on "Show/Hide EDL Events"
within "#edl_events" do
@@ -1188,8 +1188,8 @@ feature "User performs video analysis" do
open_audio_confirmation_modal
expect(page).to have_field("Origin", with: "Original Music")
expect(page).to have_content "Timecode in"
expect(page).to have_content "Source file name"
expect(page).to have_content "Timecode In"
expect(page).to have_content "Source File Name"
expect(page).to have_field("Source EDL", with: "Audio")
click_on "Show/Hide EDL Events"
@@ -1219,10 +1219,10 @@ feature "User performs video analysis" do
expect(page).to have_field("Source EDL", with: "All Tracks")
expect(page).to have_field("Channel", with: "A1")
expect(page).to have_field("Origin", with: "Library Music")
expect(page).to have_field("Timecode in", with: "01:00:00:00")
expect(page).to have_field("Timecode In", with: "01:00:00:00")
expect(page).to have_field("Timecode out", with: "01:00:02:00")
expect(page).to have_field("Duration", with: "00:00:02")
expect(page).to have_field("Source file name", with: "source_file_name.wav")
expect(page).to have_field("Source File Name", with: "source_file_name.wav")
expect(page).to have_field("Clip name", with: "clip_name")
expect(page).to have_field("Description", with: "description")
@@ -1323,8 +1323,8 @@ feature "User performs video analysis" do
open_unreleased_modal(video)
expect(page).to have_content "Timecode in"
expect(page).to have_content "Source file name"
expect(page).to have_content "Timecode In"
expect(page).to have_content "Source File Name"
click_on "Show/Hide EDL Events"
within "#edl_events" do
@@ -1371,8 +1371,8 @@ feature "User performs video analysis" do
open_unreleased_modal(video)
expect(page).to have_content "Timecode in"
expect(page).to have_content "Source file name"
expect(page).to have_content "Timecode In"
expect(page).to have_content "Source File Name"
click_on "Show/Hide EDL Events"
within "#edl_events" do
@@ -1445,7 +1445,7 @@ feature "User performs video analysis" do
first("#suggested_matches form[action='#{new_path}']").click_button
expect(page).to have_content "Timecode in"
expect(page).to have_content "Timecode In"
within "form[action='#{create_path}']" do
click_button "Confirm Release"
@@ -1462,7 +1462,7 @@ feature "User performs video analysis" do
$("#audio_matches .releasable-match button")[0].click()
JS
expect(page).to have_content "Timecode in"
expect(page).to have_content "Timecode In"
end
def select_option(select_id, text)
@@ -1486,7 +1486,7 @@ feature "User performs video analysis" do
JS
expect(page).to have_field("Origin", with: "Library Music")
expect(page).to have_content "Timecode in"
expect(page).to have_content "Timecode In"
within "form[action='#{create_path}']" do
expect(page).to have_selector("#matched_file_name", text: "library_file_name")
@@ -1518,7 +1518,7 @@ feature "User performs video analysis" do
first("form[action='#{new_path}']", text: text).click_button
expect(page).to have_content "Timecode in"
expect(page).to have_content "Timecode In"
within "form[action='#{create_path}']" do
click_button "Confirm Release"
@@ -1536,7 +1536,7 @@ feature "User performs video analysis" do
first("#music_releases form[action='#{new_path}']", text: text).click_button
expect(page).to have_field("Origin", with: "Original Music")
expect(page).to have_content "Timecode in"
expect(page).to have_content "Timecode In"
within "form[action='#{create_path}']" do
select "Vocal", from: "Music type"

View File

@@ -1,5 +1,4 @@
require 'rails_helper'
require 'zoom_gateway'
RSpec.describe ZoomGateway do
let(:roles_list_response) { {"roles" => [{"name" => 'pro-directme-host', "id" => "host_role_id"}, {"name" => 'basic-directme-host', "id" => "host_role_id"}]} }
@@ -10,7 +9,7 @@ RSpec.describe ZoomGateway do
let(:meeting_hash) { {"id" => "meeting_id", "start_url" => "https://start_url", "join_url" => "https://join_url"} }
let(:gateway) { ZoomGateway.new }
describe "constants" do
describe "pseudo-constants" do
context '.USER_TYPE_NAME' do
it 'defaults to "basic"' do
expect(ZoomGateway.USER_TYPE_NAME).to eq('basic')
@@ -65,20 +64,35 @@ RSpec.describe ZoomGateway do
end
end
context '.ACCOUNT_NUMBER' do
it 'depends on ENV["ZOOM_ACCOUNT_NUMBER"]' do
stub_env_variable('ZOOM_ACCOUNT_NUMBER', 'xxx-yyy-zzz')
expect(ZoomGateway.ACCOUNT_NUMBER).to eq('xxx-yyy-zzz')
end
end
end
describe 'static methods' do
context '.enable_recordings?' do
it 'is truthy when ZOOM_ENABLE_RECORDINGS is set to 1' do
stub_env_variable('ZOOM_ENABLE_RECORDINGS', '1')
it 'is truthy when ZOOM_ENABLE_RECORDINGS is set to true' do
stub_env_variable('ZOOM_ENABLE_RECORDINGS', 'true')
expect(ZoomGateway.enable_recordings?).to be_truthy
end
it 'is falsey otherwise' do
stub_env_variable('ZOOM_ENABLE_RECORDINGS', '0')
stub_env_variable('ZOOM_ENABLE_RECORDINGS', '1')
expect(ZoomGateway.enable_recordings?).to be_falsey
stub_env_variable('ZOOM_ENABLE_RECORDINGS', '2')
stub_env_variable('ZOOM_ENABLE_RECORDINGS', 'false')
expect(ZoomGateway.enable_recordings?).to be_falsey
end
end
context '.host_role_name' do
it 'returns given name with -directme-host prefix' do
expect(ZoomGateway.host_role_name('prefix')).to eq('prefix-directme-host')
end
end
end
describe ".find_meeting" do
@@ -117,9 +131,7 @@ RSpec.describe ZoomGateway do
end
it 'raises an exception' do
allow(ENV).to receive(:[]).and_call_original
allow(ENV).to receive(:[]).with('ZOOM_USER_TYPE').and_return('pro')
allow(ENV).to receive(:[]).with('ZOOM_PRO_USERS_LIMIT').and_return('2')
stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_PRO_USERS_LIMIT: 2)
expect { gateway.create_host('host-email@address') }.to raise_error(ZoomGateway::TooManyHosts)
end
@@ -133,11 +145,4 @@ RSpec.describe ZoomGateway do
end
end
private
def stub_env_variable(name, value)
allow(ENV).to receive(:[]).and_call_original
allow(ENV).to receive(:[]).with(name.to_s).and_return(value.to_s)
end
end

View File

@@ -130,7 +130,8 @@ RSpec.describe Account do
User,
Broadcast,
Account,
ZoomMeeting
ZoomMeeting,
MedicalRelease
]
Rails.application.eager_load!
ActiveRecord::Base.descendants.each do |model|

View File

@@ -147,10 +147,4 @@ describe AppHost do
expect(app_domain.protocol).to eq :http
end
end
private
def stub_env(key, value)
allow(ENV).to receive(:fetch).with(key).and_return(value)
end
end

View File

@@ -13,6 +13,7 @@ describe ContractTemplate do
it { is_expected.to have_many(:appearance_releases).dependent(:restrict_with_error) }
it { is_expected.to have_many(:location_releases).dependent(:restrict_with_error) }
it { is_expected.to have_many(:material_releases).dependent(:restrict_with_error) }
it { is_expected.to have_many(:medical_releases).dependent(:restrict_with_error) }
end
describe 'validations' do

View File

@@ -0,0 +1,53 @@
require "rails_helper"
RSpec.describe MedicalRelease do
it_behaves_like "a contractable"
it_behaves_like "a notable"
it_behaves_like "a photoable"
it_behaves_like "a releasable"
describe "validations" do
it { is_expected.to validate_presence_of(:person_first_name) }
it { is_expected.to validate_presence_of(:person_last_name) }
context "for #person_email" do
it { is_expected.to allow_value("test@test.com", nil).for(:person_email) }
it { is_expected.not_to allow_values("foo", "test@foo", "N/A").for(:person_email) }
end
context "for native releases" do
it { is_expected.to validate_attachment_of(:signature).on(:native) }
end
context "for non-native releases" do
it { is_expected.to validate_attachment_of(:contract).on(:non_native) }
end
end
describe "attachments" do
it { is_expected.to respond_to(:signature) }
end
describe "#uses_edl?" do
it { is_expected.not_to be_uses_edl }
end
describe "#contract_file_name" do
it "includes project name, signed at date, release type, release number and person name" do
release = create(:medical_release_with_contract_template, id: 100, signed_at: Date.new(2020, 2, 10), person_first_name: "John", person_last_name: "Doe")
expect(release.contract_file_name).to eq("my-video-project_medical_2020.02.10_1_doe-john")
end
context "when signed at is nil" do
it "uses the created at date" do
release = create(:medical_release_with_contract_template,
signed_at: nil,
created_at: DateTime.new(2020, 2, 10, 12, 0, 0),
person_first_name: "John", person_last_name: "Doe")
expect(release.contract_file_name).to eq("my-video-project_medical_2020.02.10_1_doe-john")
end
end
end
end

View File

@@ -1,5 +1,4 @@
require "rails_helper"
require "zoom_gateway"
RSpec.describe Project, type: :model do
describe "associations" do
@@ -10,6 +9,7 @@ RSpec.describe Project, type: :model do
it { is_expected.to have_many(:material_releases).dependent(:destroy) }
it { is_expected.to have_many(:music_releases).dependent(:destroy) }
it { is_expected.to have_many(:talent_releases).dependent(:destroy) }
it { is_expected.to have_many(:medical_releases).dependent(:destroy) }
it { is_expected.to have_many(:videos).dependent(:destroy) }
it { is_expected.to have_many(:contract_templates).dependent(:destroy) }
it { is_expected.to have_many(:project_memberships).dependent(:destroy) }
@@ -79,7 +79,7 @@ RSpec.describe Project, type: :model do
context 'there is no meeting' do
context 'there is a free user available' do
let!(:free_zoom_user) { create(:zoom_user, api_id: 'user_id') }
let!(:free_zoom_user) { create(:zoom_user, :with_api_id) }
before do
allow_any_instance_of(ZoomGateway).to receive(:create_meeting).and_return('new-meeting-id')

View File

@@ -1,5 +1,4 @@
require 'rails_helper'
require 'zoom_gateway'
RSpec.describe ZoomMeeting, type: :model do
let(:zoom_meeting) { build(:zoom_meeting, api_meeting_id: nil) }

View File

@@ -5,6 +5,10 @@ RSpec.describe ZoomUser, type: :model do
it { is_expected.to have_many(:zoom_meetings).dependent(:nullify) }
end
describe "enums" do
it { is_expected.to define_enum_for(:tier).with_values([:basic, :pro]) }
end
describe 'callbacks' do
let(:zoom_user) { build(:zoom_user) }
@@ -22,10 +26,120 @@ RSpec.describe ZoomUser, type: :model do
zoom_user.save
expect(zoom_user.api_id).to eq "retrieved_api_id"
end
it 'assigns current account number' do
allow_any_instance_of(ZoomGateway).to receive(:create_host).and_return("retrieved_api_id")
ENV['ZOOM_ACCOUNT_NUMBER'] = 'xxx-yyy-zzz'
zoom_user.save
expect(zoom_user.account_number).to eq 'xxx-yyy-zzz'
end
end
context '#before_destroy' do
pending 'aborts if there is api_id assigned'
end
end
describe 'scopes' do
context '.current_account' do
before do
create_list(:zoom_user, 10, :with_api_id, account_number: 'first-account-id')
create_list(:zoom_user, 25, :with_api_id, account_number: 'second-account-id')
end
it 'only returns users from currently set account' do
ENV['ZOOM_ACCOUNT_NUMBER'] = 'first-account-id'
expect(ZoomUser.current_account.count).to eq 10
expect(ZoomUser.current_account.pluck(:account_number).uniq.count).to eq 1
expect(ZoomUser.current_account.pluck(:account_number).uniq.first).to eq 'first-account-id'
end
end
context '.free' do
let(:free_user) { create(:zoom_user, :with_api_id) }
let(:busy_user) { create(:zoom_user, :with_api_id) }
let(:second_busy_user) { create(:zoom_user, :with_api_id) }
let!(:meeting_started) { create(:zoom_meeting, zoom_user: busy_user, status: :started) }
let!(:meeting_created) { create(:zoom_meeting, zoom_user: second_busy_user, status: :created) }
it 'returns only the users without started / created meetings' do
users = ZoomUser.free
expect(users).to include(free_user)
expect(users).not_to include(busy_user)
expect(users).not_to include(second_busy_user)
end
end
end
describe '.current_account?' do
let(:zoom_user) { create(:zoom_user, :with_api_id, account_number: 'xxx-xxx-xxx') }
it 'returns true if it belongs to currently set account' do
ENV['ZOOM_ACCOUNT_NUMBER'] = 'xxx-xxx-xxx'
expect(zoom_user.current_account?).to be_truthy
end
it 'returns false if it doesn\'t belong to currently set account' do
ENV['ZOOM_ACCOUNT_NUMBER'] = 'yyy-yyy-yyy'
expect(zoom_user.current_account?).to be_falsey
end
end
context 'static methods' do
describe '.generate_api_email' do
it 'contains @' do
expect(ZoomUser.generate_api_email).to include('@')
end
end
describe '.for_new_meeting' do
let(:a_basic) { create(:zoom_user, :with_api_id, account_number: 'aaa', tier: :basic) }
let(:b_basic) { create(:zoom_user, :with_api_id, account_number: 'bbb', tier: :basic) }
let(:a_pro) { create(:zoom_user, :with_api_id, account_number: 'aaa', tier: :pro) }
let(:b_pro) { create(:zoom_user, :with_api_id, account_number: 'bbb', tier: :pro) }
it 'picks free user of requested type from current account' do
[a_basic, a_pro, b_basic, b_pro]
stub_env_variables(ZOOM_USER_TYPE: 'basic', ZOOM_ACCOUNT_NUMBER: 'aaa')
expect(ZoomUser.for_new_meeting).to eq(a_basic)
stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_ACCOUNT_NUMBER: 'aaa')
expect(ZoomUser.for_new_meeting).to eq(a_pro)
stub_env_variables(ZOOM_USER_TYPE: 'basic', ZOOM_ACCOUNT_NUMBER: 'bbb')
expect(ZoomUser.for_new_meeting).to eq(b_basic)
stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_ACCOUNT_NUMBER: 'bbb')
expect(ZoomUser.for_new_meeting).to eq(b_pro)
end
context 'no free user' do
before do
allow_any_instance_of(ZoomGateway).to receive(:create_host).and_return('host-id')
end
it 'creates new user if there is no requested user free available under account' do
[a_basic, a_pro, b_basic]
stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_ACCOUNT_NUMBER: 'bbb')
expect_any_instance_of(ZoomGateway).to receive(:create_host)
ZoomUser.for_new_meeting
end
it 'creates new user if requested user is busy' do
[a_basic, a_pro, b_basic, b_pro]
stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_ACCOUNT_NUMBER: 'aaa')
create(:zoom_meeting, zoom_user: a_pro, status: :started)
expect_any_instance_of(ZoomGateway).to receive(:create_host)
ZoomUser.for_new_meeting
end
end
end
end
end

View File

@@ -0,0 +1,37 @@
require "rails_helper"
describe MedicalReleasePolicy do
let(:user_context) { build(:user_context) }
subject { described_class }
permissions :create? do
it { is_expected.to permit(:create) }
end
permissions :show? do
it { is_expected.to permit(:show) }
end
permissions :update? do
context "for a native release" do
it { is_expected.not_to permit(user_context, build(:medical_release, :native)) }
end
context "for a non-native release" do
it { is_expected.to permit(user_context, build(:medical_release, :non_native)) }
end
end
permissions :destroy? do
it { is_expected.to permit(:destroy) }
end
permissions :edit_photos? do
it { is_expected.to permit(:edit_photos) }
end
permissions :update_photos? do
it { is_expected.to permit(:update_photos) }
end
end

View File

@@ -0,0 +1,16 @@
module EnvHelper
def stub_env_variables(vars)
allow(ENV).to receive(:[]).and_call_original
vars.each do |variable, value|
allow(ENV).to receive(:[]).with(variable.to_s).and_return(value)
end
end
def stub_env_variable(key, value)
stub_env_variables({key => value})
end
end
RSpec.configure do |config|
config.include EnvHelper
end