Compare commits

...

5 Commits

Author SHA1 Message Date
Senad Uka
9a29f1d13a Usptream sync castme 2020-07-29 05:15:44 +00:00
Senad Uka
4f1ebb27d0 Upstream sync 2020-07-27 10:18:49 +00:00
Senad Uka
95e9a70c4b Upstream cast me sync 2020-07-22 13:37:34 +00:00
Senad Uka
e3acdb4d0e Cast me sync 2020-07-17 04:50:04 +02:00
Senad Uka
96b31b71cf cast me sync 2020-07-16 18:03:37 +02:00
69 changed files with 1373 additions and 791 deletions

View File

@@ -11,6 +11,7 @@ $body-color: #4A4A4A;
$primary: #6F89FF;
$blue: #0092ff;
$red: #F9002B;
$dark-red: #CE004A;
$green: #51B61B;
$teal: #32C498;
$purple: #5139EE;

View File

@@ -69,6 +69,13 @@ label {
}
}
&.cast-me {
span:last-child {
background-color: $dark-red;
color: $white;
}
}
&.disabled {
span:last-child {
background-color: $gray-500 !important;

View File

@@ -1,64 +0,0 @@
class Admin::CastingCallInterviewsController < Admin::ApplicationController
before_action :set_casting_call_interview, only: [:edit, :update, :show, :complete]
before_action :build_casting_call_interview, only: [:new, :create]
def index
@casting_call_interviews = casting_call_interviews.order_by_recent.paginate(page: params[:page])
end
def new
@accounts = accounts
end
def create
@casting_call_interview.attributes = casting_call_interview_params
if @casting_call_interview.save
redirect_to [:admin, :casting_call_interviews], notice: t(".notice")
else
render :new
end
end
def edit
@accounts = accounts
end
def update
if @casting_call_interview.update(casting_call_interview_params)
redirect_to [:admin, :casting_call_interviews], notice: t(".notice")
else
render :edit
end
end
def complete
if @casting_call_interview.update(interviewed_at: Time.zone.now)
redirect_to [:admin, :casting_call_interviews], notice: t(".notice")
else
redirect_to [:admin, :casting_call_interviews], notice: t(".alert")
end
end
private
def casting_call_interview_params
params.require(:casting_call_interview).permit(:casting_call_id, :performer_name, :interview_date, :zoom_meeting_url)
end
def casting_call_interviews
policy_scope CastingCallInterview
end
def set_casting_call_interview
@casting_call_interview = authorize policy_scope(CastingCallInterview).find(params[:id])
end
def accounts
policy_scope Account
end
def build_casting_call_interview
@casting_call_interview = authorize policy_scope(CastingCallInterview).build
end
end

View File

@@ -0,0 +1,70 @@
class Admin::CastingSubmissionsController < Admin::ApplicationController
before_action :set_casting_submission, only: [:edit, :update, :show, :complete]
before_action :build_casting_submission, only: [:new, :create]
before_action :set_accounts, only: %i[new create edit]
def index
@casting_submissions = casting_submissions.order_by_recent.paginate(page: params[:page])
end
def create
@casting_submission.attributes = casting_submission_params
if @casting_submission.save
redirect_to [:admin, :casting_submissions], notice: t(".notice")
else
render :new
end
end
def update
if @casting_submission.update(casting_submission_params)
redirect_to [:admin, :casting_submissions], notice: t(".notice")
else
render :edit
end
end
def complete
if @casting_submission.update(interviewed_at: Time.zone.now)
redirect_to [:admin, :casting_submissions], notice: t(".notice")
else
redirect_to [:admin, :casting_submissions], notice: t(".alert")
end
end
private
def set_accounts
@accounts = accounts
end
def casting_submission_params
params.require(:casting_submission).permit(
:casting_call_id, :performer_name, :interview_date,
:zoom_meeting_url, :interview_recording, :time_elapsed_1,
:time_elapsed_2, :time_elapsed_3, :time_elapsed_4, :time_elapsed_5,
:time_elapsed_6, :time_elapsed_7, :time_elapsed_8, :time_elapsed_9,
:time_elapsed_10, :time_elapsed_11, :time_elapsed_12, :time_elapsed_13,
:time_elapsed_14, :time_elapsed_15, :note_1 , :note_2 , :note_3 , :note_4,
:note_5, :note_6, :note_7, :note_8, :note_9, :note_10, :note_11, :note_12, :note_13,
:note_14, :note_15
)
end
def casting_submissions
policy_scope CastingSubmission
end
def set_casting_submission
@casting_submission = authorize policy_scope(CastingSubmission).find(params[:id])
end
def accounts
policy_scope Account
end
def build_casting_submission
@casting_submission = authorize policy_scope(CastingSubmission).build
end
end

View File

@@ -1,28 +0,0 @@
class CastingCallInterviewsController < ApplicationController
before_action :set_project
before_action :set_casting_call_interview, only: [:show]
include ProjectLayout
def index
@casting_call_interviews = casting_call_interviews.completed.order_by_recent.paginate(page: params[:page])
end
def show
@files = @casting_call_interview.files.paginate(page: params[:page])
end
private
def set_project
@project = policy_scope(Project).find(params[:project_id])
end
def set_casting_call_interview
@casting_call_interview = authorize casting_call_interviews.find(params[:id])
end
def casting_call_interviews
authorize policy_scope(CastingCallInterview)
end
end

View File

@@ -4,6 +4,7 @@ class CastingCallsController < ApplicationController
before_action :set_project
before_action :build_casting_call, only: [:new, :create]
before_action :set_casting_call, only: [:show, :edit, :update, :cancel]
before_action :show_splash_screen, only: :index
def index
@casting_calls = casting_calls.order_by_recent.paginate(page: params[:page])
@@ -17,8 +18,7 @@ class CastingCallsController < ApplicationController
if @casting_call.save
log_create_analytics
castme_url = url_for([@project, @casting_call])
SubmitHubspotFormJob.perform_later(email: @casting_call.user_email, castme_url: castme_url, form_guid: ENV["HUBSPOT_CASTING_CALL_REQUEST_FORM_GUID"])
redirect_to [@project, :casting_calls], notice: t(".notice")
else
render :new
end
@@ -46,6 +46,10 @@ class CastingCallsController < ApplicationController
private
def show_splash_screen
render :splash if casting_calls.count.zero?
end
def casting_call_params
params.require(:casting_call).permit(:title, :description, :project_description, :interview_instructions, :interview_requirements, :questions)
end

View File

@@ -0,0 +1,30 @@
class CastingSubmissionDownloadsController < ApplicationController
include ProjectContext
before_action :set_project, only: [:create]
before_action :set_casting_submission, only: :create
include ProjectLayout
def create
download = @project.downloads.create!(name: @casting_submission.zip_file_name, release_type: "CastingSubmission")
other_downloads_in_progress = @project.downloads.unfinished_desc_order.offset(1)
if other_downloads_in_progress.any?
in_progress_downloads_details = render_to_string "_other_pending_downloads", locals: { downloads: other_downloads_in_progress, release_type: "CastingSubmission" }, :layout => false
ProjectsChannel.broadcast_download_generation_update(download, in_progress_downloads_details)
else
ProjectsChannel.broadcast_download_generation_update(download, I18n.t("casting_submission_downloads.download.pending", release_type: "CastingSubmission"))
end
GenerateCastingSubmissionFilesZipJob.perform_later(@project, download, @casting_submission)
end
private
def set_casting_submission
authorize(Download)
@casting_submission = policy_scope(@project.casting_submissions).find(params[:casting_submission_id])
end
end

View File

@@ -0,0 +1,32 @@
class CastingSubmissionsController < ApplicationController
before_action :set_project
before_action :set_casting_submission, only: [:show]
include ProjectLayout
def index
@casting_submissions = casting_submissions.completed.order_by_recent.paginate(page: params[:page])
end
def show
@casting_call = @casting_submission.casting_call
@files = @casting_submission.files.order("created_at DESC").paginate(page: params[:files_page])
@markers = @casting_submission.markers
render layout: 'application'
end
private
def set_project
@project = policy_scope(Project).find(params[:project_id])
end
def set_casting_submission
@casting_submission = authorize casting_submissions.find(params[:id])
end
def casting_submissions
authorize policy_scope(CastingSubmission)
end
end

View File

@@ -1,30 +0,0 @@
class InterviewDownloadsController < ApplicationController
include ProjectContext
before_action :set_project, only: [:create]
before_action :set_casting_call_interview, only: :create
include ProjectLayout
def create
download = @project.downloads.create!(name: @casting_call_interview.zip_file_name, release_type: "CastingCallInterview")
other_downloads_in_progress = @project.downloads.unfinished_desc_order.offset(1)
if other_downloads_in_progress.any?
in_progress_downloads_details = render_to_string "_other_pending_downloads", locals: { downloads: other_downloads_in_progress, release_type: "CastingCallInterview" }, :layout => false
ProjectsChannel.broadcast_download_generation_update(download, in_progress_downloads_details)
else
ProjectsChannel.broadcast_download_generation_update(download, I18n.t("interview_downloads.download.pending", release_type: "Casting Call Interview"))
end
GenerateInterviewFilesZipJob.perform_later(@project, download, @casting_call_interview)
end
private
def set_casting_call_interview
authorize(Download)
@casting_call_interview = policy_scope(@project.casting_call_interviews).find(params[:casting_call_interview_id])
end
end

View File

@@ -1,25 +0,0 @@
class Public::CastingCallInterviewsController < Public::BaseController
skip_after_action :verify_authorized
before_action :set_casting_call_interview, only: [:show, :update]
def show
end
def update
if @casting_call_interview.update(casting_call_interview_params)
redirect_to casting_call_interview_url(token: @casting_call_interview.token), notice: t(".notice")
else
render :show
end
end
private
def set_casting_call_interview
@casting_call_interview = CastingCallInterview.find_by_token(params[:token])
end
def casting_call_interview_params
params.require(:casting_call_interview).permit(files: [])
end
end

View File

@@ -0,0 +1,25 @@
class Public::CastingSubmissionsController < Public::BaseController
skip_after_action :verify_authorized
before_action :set_casting_submission, only: [:show, :update]
def show
end
def update
if @casting_submission.update(casting_submission_params)
redirect_to casting_submission_url(token: @casting_submission.token), notice: t(".notice")
else
render :show
end
end
private
def set_casting_submission
@casting_submission = CastingSubmission.find_by_token(params[:token])
end
def casting_submission_params
params.require(:casting_submission).permit(files: [])
end
end

View File

@@ -1,4 +1,4 @@
class GenerateInterviewFilesZipJob < ApplicationJob
class GenerateCastingSubmissionFilesZipJob < ApplicationJob
queue_as :default
include Rails.application.routes.url_helpers
include ActionView::Helpers::UrlHelper
@@ -6,12 +6,12 @@ class GenerateInterviewFilesZipJob < ApplicationJob
before_perform do |job|
@project = job.arguments.first
@download = job.arguments.second
@casting_call_interview = job.arguments.third
@casting_submission = job.arguments.third
@download.update!(status: :pending)
end
def perform(project, download, casting_call_interview)
::InterviewFilesCollectionService.new(casting_call_interview.files, @download.name).build do |dir, files|
def perform(project, download, casting_submission)
::CastingSubmissionFilesCollectionService.new(casting_submission.files, @download.name).build do |dir, files|
zipfile_name = "#{dir}/#{@download.name}.zip"
Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
files.each do |attachment|
@@ -24,11 +24,11 @@ class GenerateInterviewFilesZipJob < ApplicationJob
rescue StandardError => e
Raven.extra_context(
message: "Failed to generate download for project (##{project.id})",
release_type: "CastingCallInterview"
release_type: "CastingSubmission"
)
@download.failure!
ProjectsChannel.broadcast_download_generation_update(@download, I18n.t("interview_downloads.download.failure"))
ProjectsChannel.broadcast_download_generation_update(@download, I18n.t("casting_submission_downloads.download.failure"))
end
after_perform do |job|
@@ -37,7 +37,7 @@ class GenerateInterviewFilesZipJob < ApplicationJob
downloads_folder_link = link_to("Files > Downloads", project_downloads_path(I18n.locale, @project))
download_button = link_to("Download", rails_blob_path(@download.file, disposition: "attachment", only_path: true), class: "btn btn-success", target: :_blank)
ProjectsChannel.broadcast_download_generation_update(@download, I18n.t("interview_downloads.download.success", downloads_folder_link: downloads_folder_link, download_button: download_button, release_type: "Casting Call Interview"))
ProjectsChannel.broadcast_download_generation_update(@download, I18n.t("casting_submission_downloads.download.success", downloads_folder_link: downloads_folder_link, download_button: download_button, release_type: "Casting Submission"))
end
end
end

View File

@@ -5,7 +5,7 @@ class Account < ApplicationRecord
has_many :users, through: :account_auths
has_many :projects, dependent: :destroy
has_many :casting_calls, through: :projects
has_many :casting_call_interviews, through: :projects
has_many :casting_submissions, through: :projects
has_many :videos, through: :projects
has_many :contract_templates, through: :projects
@@ -62,7 +62,7 @@ class Account < ApplicationRecord
MiscRelease.where(project: projects),
MatchingRequest.where(project: projects),
CastingCall.where(project: projects),
self.casting_call_interviews,
self.casting_submissions,
self
])).sum(:byte_size).to_f
end

View File

@@ -1,6 +1,6 @@
class CastingCall < ApplicationRecord
belongs_to :project
has_many :casting_call_interviews, dependent: :destroy
has_many :casting_submissions, dependent: :destroy
has_secure_token

View File

@@ -1,22 +0,0 @@
class CastingCallInterview < ApplicationRecord
belongs_to :casting_call
has_many_attached :files
has_secure_token
validates :performer_name, presence: true
scope :completed, -> { where.not(interviewed_at: nil) }
def join_zoom_meeting_url
uri = URI.parse(self.zoom_meeting_url)
zoom_meeting_id = uri.path.gsub("/j/", "")
zoom_meeting_pwd = uri.query.gsub("pwd=", "")
"zoommtg://zoom.us/join?confno=#{zoom_meeting_id}&pwd=#{zoom_meeting_pwd}"
end
def zip_file_name
"#{self.casting_call.title.parameterize}_#{self.performer_name.parameterize}_#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}"
end
end

View File

@@ -0,0 +1,25 @@
class CastingSubmission < ApplicationRecord
belongs_to :casting_call
has_many_attached :files
has_one_attached :interview_recording
NUMBER_OF_MARKER_FIELDS = 15
has_secure_token
validates :performer_name, presence: true
scope :completed, -> { where.not(interviewed_at: nil) }
def zip_file_name
"#{self.casting_call.title.parameterize}_#{self.performer_name.parameterize}_#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}"
end
def markers
(1..NUMBER_OF_MARKER_FIELDS).map do |n|
if public_send("time_elapsed_#{n}").present?
OpenStruct.new(id: n, time_elapsed: public_send("time_elapsed_#{n}"), note: public_send("note_#{n}") )
end
end.compact
end
end

View File

@@ -16,7 +16,7 @@ class Project < ApplicationRecord
has_many :medical_releases, dependent: :destroy
has_many :misc_releases, dependent: :destroy
has_many :casting_calls, dependent: :destroy
has_many :casting_call_interviews, through: :casting_calls
has_many :casting_submissions, through: :casting_calls
has_many :videos, dependent: :destroy
has_many :imports, dependent: :destroy
has_many :contract_templates, dependent: :destroy

View File

@@ -1,4 +1,4 @@
class CastingCallInterviewPolicy < ApplicationPolicy
class CastingSubmissionPolicy < ApplicationPolicy
def index?
true
end

View File

@@ -41,7 +41,7 @@ class ProjectPolicy < ApplicationPolicy
show?
end
def show_casting_call_interview_results?
def show_casting_submission_results?
show?
end
end

View File

@@ -1,4 +1,4 @@
class InterviewFilesCollectionService
class CastingSubmissionFilesCollectionService
def initialize(files, folder_name)
@files = files
@folder_name = folder_name
@@ -21,4 +21,4 @@ class InterviewFilesCollectionService
private
attr_reader :files, :folder_name
end
end

View File

@@ -11,7 +11,7 @@
<%= link_to fa_icon("tasks fw", text: "Task Requests"), [:admin, :task_requests], class: class_string("nav-link", "active" => controller_name == "task_requests") %>
</li>
<li class="nav-item">
<%= link_to fa_icon("video-camera fw", text: "Casting Call Interviews"), [:admin, :casting_call_interviews], class: class_string("nav-link", "active" => controller_name == "casting_call_interviews") %>
<%= link_to fa_icon("video-camera fw", text: "Casting Submissions"), [:admin, :casting_submissions], class: class_string("nav-link", "active" => controller_name == "casting_submissions") %>
</li>
<li class="nav-item">
<%= link_to fa_icon("bug fw", text: "Errors"), "https://sentry.io/bigmedia/", class: "nav-link", target: :_blank %>

View File

@@ -1,26 +0,0 @@
<tr id="<%= dom_id(casting_call_interview) %>">
<td>
<%= casting_call_interview.casting_call.project.account.name.titleize %>
</td>
<td>
<%= casting_call_interview.casting_call.title.titleize %>
</td>
<td>
<%= casting_call_interview.performer_name %>
</td>
<td>
<%= casting_call_interview.interview_date %>
</td>
<td class="text-right">
<div class="btn-group">
<%= button_tag "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">
<%= link_to fa_icon("video-camera", text: "View"), casting_call_interview_url(token: casting_call_interview.token), target: "_blank", class: "dropdown-item" %>
<%= link_to fa_icon("pencil", text: "Edit"), [:edit, :admin, casting_call_interview], class: "dropdown-item" %>
<% unless casting_call_interview.interviewed_at.present? %>
<%= link_to fa_icon("check", text: "Complete"), [:complete, :admin, casting_call_interview], method: :post, class: "dropdown-item" %>
<% end %>
</div>
</div>
</td>
</tr>

View File

@@ -1,15 +0,0 @@
<%= errors_summary_for casting_call_interview %>
<%= bootstrap_form_with model: model, local: true do |form| %>
<%= form.text_field :performer_name, required: true %>
<%= form.grouped_collection_select(:casting_call_id, @accounts, :casting_calls, :name, :id, :title, { prompt: "Select a Casting Call", required: true, class: "form-control custom-select" }) %>
<%= form.text_field :interview_date, class: "datepicker-control" %>
<%= form.text_field :zoom_meeting_url %>
<div class="row align-items-center text-center mt-4">
<%= link_to t("shared.cancel"), [:admin, :casting_call_interviews], class: "col-3 text-reset" %>
<div class="col-9">
<%= form.submit class: class_string("btn btn-block", ["btn-success", "btn-primary"] => casting_call_interview.new_record?), data: { disable_with: t("shared.disable_with") } %>
</div>
</div>
<% end %>

View File

@@ -1,6 +0,0 @@
<div class="card shadow-sm">
<%= card_header text: "Edit Casting Call Interview", close_action_path: [:admin, :casting_call_interviews] %>
<div class="card-body">
<%= render "form", model: [:admin, @casting_call_interview], casting_call_interview: @casting_call_interview %>
</div>
</div>

View File

@@ -1,6 +0,0 @@
<div class="card shadow-sm">
<%= card_header text: t(".heading"), close_action_path: [:admin, :casting_call_interviews] %>
<div class="card-body">
<%= render "form", model: [:admin, @casting_call_interview], casting_call_interview: @casting_call_interview, casting_calls: @casting_calls %>
</div>
</div>

View File

@@ -0,0 +1,27 @@
<tr id="<%= dom_id(casting_submission) %>">
<td>
<%= casting_submission.casting_call.project.account.name.titleize %>
</td>
<td>
<%= casting_submission.casting_call.title.titleize %>
</td>
<td>
<%= casting_submission.performer_name %>
</td>
<td>
<%= casting_submission.interview_date %>
</td>
<td class="text-right">
<div class="btn-group">
<%= button_tag "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">
<%= link_to fa_icon("video-camera", text: "View"), casting_submission_url(token: casting_submission.token), target: "_blank", class: "dropdown-item" %>
<%= link_to fa_icon("pencil", text: "Edit"), [:edit, :admin, casting_submission], class: "dropdown-item" %>
<% unless casting_submission.interviewed_at.present? %>
<%= link_to fa_icon("check", text: "Complete"), [:complete, :admin, casting_submission], method: :post, class: "dropdown-item" %>
<% end %>
<%= link_to fa_icon("link fw", text: "Copy URL"), casting_submission_url(token: casting_submission.token), class: "dropdown-item", data: { behavior: "clipboard" } %>
</div>
</div>
</td>
</tr>

View File

@@ -0,0 +1,37 @@
<%= errors_summary_for casting_submission %>
<%= bootstrap_form_with model: model, local: true do |form| %>
<%= form.text_field :performer_name, required: true %>
<%= form.grouped_collection_select(:casting_call_id, @accounts, :casting_calls, :name, :id, :title, { prompt: "Select a Casting Call", required: true, class: "form-control custom-select" }) %>
<%= form.text_field :interview_date, class: "datepicker-control" %>
<%= form.text_field :zoom_meeting_url %>
<% unless casting_submission.new_record? %>
<%= form.file_field :interview_recording, accept: "video/mp4", data: { direct_upload_url: rails_direct_uploads_url, aws_bucket: ENV['AWS_BUCKET'], aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'], signer_url: multipart_signatures_url } %>
<% if casting_submission.interview_recording.attached? %>
<p>
<%= link_to casting_submission.interview_recording do %>
<%= fa_icon "file-text-o" %> <%= casting_submission.interview_recording.filename %>
<% end %>
<span class="text-muted"><%= fa_icon "long-arrow-left" %> <em>Current interview recording</em></span>
</p>
<% end %>
<hr>
<%= card_field_set_tag t(".casting_submission_markers.heading") do %>
<% (1..CastingSubmission::NUMBER_OF_MARKER_FIELDS).each do |n| %>
<div class="form-row">
<%= form.number_field "time_elapsed_#{n}", wrapper_class: "col-md-6", label: "Elapsed Time #{n} (in seconds)" %>
<%= form.text_area "note_#{n}", wrapper_class: "col-md-6", label: "Note #{n}" %>
</div>
<% end %>
<% end %>
<% end %>
<div class="row align-items-center text-center mt-4">
<%= link_to t("shared.cancel"), [:admin, :casting_submissions], class: "col-3 text-reset" %>
<div class="col-9">
<%= form.submit class: class_string("btn btn-block", ["btn-success", "btn-primary"] => casting_submission.new_record?), data: { disable_with: t("shared.disable_with") } %>
</div>
</div>
<% end %>

View File

@@ -0,0 +1,6 @@
<div class="card shadow-sm">
<%= card_header text: "Edit Casting Submission", close_action_path: [:admin, :casting_submissions] %>
<div class="card-body">
<%= render "form", model: [:admin, @casting_submission], casting_submission: @casting_submission %>
</div>
</div>

View File

@@ -1,6 +1,6 @@
<div class="d-flex flex-row justify-content-between align-items-center mb-3">
<% if policy(CastingCall).new? %>
<%= link_to fa_icon("plus", text: t(".actions.new")), [:new, :admin, :casting_call_interview], class: "btn btn-primary mb-3" %>
<%= link_to fa_icon("plus", text: t(".actions.new")), [:new, :admin, :casting_submission], class: "btn btn-primary mb-3" %>
<% end %>
</div>
@@ -16,8 +16,8 @@
</tr>
</thead>
<tbody id="users">
<% if @casting_call_interviews.any? %>
<%= render @casting_call_interviews %>
<% if @casting_submissions.any? %>
<%= render @casting_submissions %>
<% else %>
<tr>
<td colspan="20" class="py-4 text-center text-muted"><%= t(".empty") %></td>
@@ -27,6 +27,6 @@
</table>
</div>
<div id="casting_call_interviews_pagination" class="mt-3">
<%= will_paginate @casting_call_interviews %>
<div id="casting_submissions_pagination" class="mt-3">
<%= will_paginate @casting_submissions %>
</div>

View File

@@ -0,0 +1,6 @@
<div class="card shadow-sm">
<%= card_header text: t(".heading"), close_action_path: [:admin, :casting_submissions] %>
<div class="card-body">
<%= render "form", model: [:admin, @casting_submission], casting_submission: @casting_submission, casting_calls: @casting_calls %>
</div>
</div>

View File

@@ -1,27 +0,0 @@
<tr id="<%= dom_id(casting_call_interview) %>">
<td>
<%= casting_call_interview.casting_call.project.account.name.titleize %>
</td>
<td>
<%= casting_call_interview.casting_call.title&.titleize %>
</td>
<td>
<%= casting_call_interview.performer_name %>
</td>
<td>
<%= casting_call_interview.interviewed_at %>
</td>
<td class="text-right">
<div class="btn-group">
<%= button_tag "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(CastingCallInterview).show? %>
<%= link_to fa_icon("video-camera", text: "View"), [@project, casting_call_interview], target: "_blank", class: "dropdown-item" %>
<% end %>
<% if policy(CastingCallInterview).download? %>
<%= link_to fa_icon("download", text: "Download"), [@project, :interview_downloads, casting_call_interview_id: casting_call_interview.id], method: :post, remote: true, class: "dropdown-item" %>
<% end %>
</div>
</div>
</td>
</tr>

View File

@@ -1,6 +0,0 @@
<tr>
<td><%= file.filename %></td>
<td class="text-right">
<%= link_to fa_icon("download"), file, target: "_blank" %>
</td>
</tr>

View File

@@ -1,25 +0,0 @@
<div class="col-md-12">
<h2 class="h6 mt-3">Files:</h2>
<div class="pt-2 mx-n3">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th>Filename</th>
<th></th>
</tr>
</thead>
<tbody id="task_requests">
<% if @files.any? %>
<%= render partial: "file", collection: @files %>
<% else %>
<tr>
<td colspan="12" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
<div class="mt-4" id="task_requests_pagiantion">
<%= will_paginate @files %>
</div>
</div>
</div>

View File

@@ -6,12 +6,14 @@
<strong><%= t '.info_message' %></strong>
</div>
<%= form.text_field :title, label: t('.labels.title') %>
<%= form.text_area :description, label: t('.labels.description') %>
<%= form.text_area :project_description, label: t('.labels.project_description') %>
<%= form.text_area :interview_instructions, label: t('.labels.interview_instructions') %>
<%= form.text_area :interview_requirements, label: t('.labels.interview_requirements') %>
<%= form.text_area :questions, label: t('.labels.questions') %>
<%= form.text_field :title %>
<%= form.text_area :description %>
<%= form.text_area :project_description %>
<%= field_set_tag t(".headings.chatbot") do %>
<%= form.text_area :interview_instructions, rows: 6 %>
<%= form.text_area :questions, rows: 8 %>
<%= form.text_area :interview_requirements, rows: 6 %>
<% end %>
<div class="row align-items-center text-center mt-4">
<%= link_to t("shared.cancel"), [project, :casting_calls], class: "col-3 text-reset" %>
@@ -19,4 +21,4 @@
<%= form.submit class: class_string("btn btn-block", ["btn-success", "btn-primary"] => casting_call.new_record?), data: { disable_with: t("shared.disable_with") } %>
</div>
</div>
<% end %>
<% end %>

View File

@@ -1,2 +0,0 @@
<%= render "shared/initiate_hubspot_chat" %>
<p class="alert alert-success p-3 lead text-center"><%= t '.success_message' %></p>

View File

@@ -0,0 +1,58 @@
<div class="d-flex flex-row">
<div class="d-flex flex-column">
<%= product_wordmark :cast_me, prefix: t('.headings.welcome'), class: "h2" %>
<p class="text-muted"><%= t '.headings.subtitle' %>
</div>
<%= link_to t(".actions.book_demo"), 'https://meetings.hubspot.com/bray2', class: "btn btn-primary border align-self-center h-50 ml-auto mr-2 pb-2", target: '_blank' %>
<% if policy(CastingCall).new? %>
<%= link_to t(".actions.create_casting_call"), [:new, @project, :casting_call], class: "btn btn-success border align-self-center h-50 pb-2" %>
<% end %>
</div>
<hr>
<div class="pt-2">
<div class="row">
<div class="col">
<div class="card-body p-0">
<div class="embed-responsive embed-responsive-16by9">
<div class="embed-responsive-item">
<table class="w-100 h-100 bg-secondary">
<tbody>
<tr>
<td class="text-center align-middle text-white">
Video tutorial will be available soon
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="col">
<div class="row">
<div class="col">
<h3><%= t '.headings.how_it_works' %></h3>
<ol>
<li><%= t '.list_items.enter_information' %></li>
<li><%= t '.list_items.enter_questions' %></li>
<li><%= t '.list_items.copy_and_paste_submission_link' %></li>
<li><%= t '.list_items.wait_for_the_submission_video' %></li>
</ol>
</div>
</div>
<div class="row">
<div class="col">
<h3><%= t '.headings.benefits' %></h3>
<ul class="fa-ul ml-5">
<%= content_tag(:li, fa_icon("check li", text: t('.list_items.fewer_team_members_needed'))) %>
<%= content_tag(:li, fa_icon("check li", text: t('.list_items.fewer_resources_needed'))) %>
<%= content_tag(:li, fa_icon("check li", text: t('.list_items.more_time_spent_with_quality_candidates'))) %>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@@ -6,7 +6,7 @@
<% if download.release_type == "reports"%>
<li><%= download.release_type.titleize %> (as of <%= time_ago_in_words(download.created_at) %> ago)
</li>
<% elsif download.release_type == "CastingCallInterview"%>
<% elsif download.release_type == "CastingSubmission"%>
<li><%= download.release_type.titleize %> files (as of <%= time_ago_in_words(download.created_at) %> ago)
</li>
<% else %>

View File

@@ -0,0 +1,27 @@
<tr id="<%= dom_id(casting_submission) %>">
<td>
<%= casting_submission.casting_call.project.account.name.titleize %>
</td>
<td>
<%= casting_submission.casting_call.title&.titleize %>
</td>
<td>
<%= casting_submission.performer_name %>
</td>
<td>
<%= casting_submission.interviewed_at %>
</td>
<td class="text-right">
<div class="btn-group">
<%= button_tag "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(CastingSubmission).show? %>
<%= link_to fa_icon("video-camera", text: "View"), [@project, casting_submission], target: "_blank", class: "dropdown-item" %>
<% end %>
<% if policy(CastingSubmission).download? %>
<%= link_to fa_icon("download", text: "Download"), [@project, :casting_submission_downloads, casting_submission_id: casting_submission.id], method: :post, remote: true, class: "dropdown-item" %>
<% end %>
</div>
</div>
</td>
</tr>

View File

@@ -0,0 +1,12 @@
<li class="my-2" id="<%= dom_id(file) %>">
<% if file.variable? %>
<%= link_to image_tag(file.variant(resize_and_pad: [300, 300, background: "#F7F8F9"]), class: "bg-light img-thumbnail img-fluid"), file, target: "_blank" %>
<% else %>
<div class="border rounded bg-light text-muted d-flex justify-content-center align-items-center fix-h-and-w">
<%= link_to file, target: "_blank" do %>
<%= fa_icon("file", style: "font-size: 2rem") %>
<div class="mt-2"><%= file.filename %></div>
<% end %>
</div>
<% end %>
</li>

View File

@@ -0,0 +1,14 @@
<div class="overflow-auto mh-30">
<ul class="list-unstyled d-flex flex-column align-items-center text-center" id="casting_submission_file_list_<%= casting_submission.id %>">
<% if files.present? %>
<%= render partial: "casting_submissions/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="casting_submission_files_pagination_<%= casting_submission.id %>">
<%= will_paginate(files, param_name: 'files_page', params: { active_files_tab: casting_submission.id }) if files.present? %>
</div>
</div>

View File

@@ -0,0 +1,15 @@
<% if casting_submission.interview_recording.present? %>
<div id="casting_submission_video" class="embed-responsive-item"></div>
<% else %>
<div id="casting_submission_video" class="embed-responsive-item">
<table class="w-100 h-100 bg-secondary">
<tbody>
<tr>
<td class="text-center align-middle text-white">
Video player will appear here when the interview recording is available.
</td>
</tr>
</tbody>
</table>
</div>
<% end %>

View File

@@ -10,8 +10,8 @@
</tr>
</thead>
<tbody id="users">
<% if @casting_call_interviews.any? %>
<%= render @casting_call_interviews %>
<% if @casting_submissions.any? %>
<%= render @casting_submissions %>
<% else %>
<tr>
<td colspan="20" class="py-4 text-center text-muted"><%= t(".empty") %></td>
@@ -21,6 +21,6 @@
</table>
</div>
<div id="casting_call_interviews_pagination" class="mt-3">
<%= will_paginate @casting_call_interviews %>
<div id="casting_submissions_pagination" class="mt-3">
<%= will_paginate @casting_submissions %>
</div>

View File

@@ -0,0 +1,92 @@
<% content_for :header do %>
<header class="container-fluid py-3 border-bottom sticky-top bg-light">
<div class="row align-items-center justify-content-center">
<div class="col-4 text-center">
<%= product_wordmark(:cast_me, class: 'navbar-brand') %>
</div>
</div>
</header>
<% end %>
<div class="row">
<div class="col-lg-8 col-md-12 mb-3">
<div class="card shadow-sm">
<div class="card-header">
<div class="d-flex justify-content-start flex-column">
<h1 class="h2 mb-1"><%= @casting_submission.performer_name %></h1>
<h1 class="h6 mb-1"><%= @casting_call.title %></h1>
</div>
</div>
<div class="card-body p-0">
<div class="embed-responsive embed-responsive-16by9">
<%= render partial: 'casting_submissions/video', locals: { casting_submission: @casting_submission } %>
<% if @casting_submission.interview_recording.present? %>
<%= javascript_tag nonce: true do %>
var markerData = <%= raw @markers.to_json %>;
var player = new Clappr.Player({
parentId: '#casting_submission_video',
source: "<%= rails_blob_url(@casting_submission.interview_recording, host: AppHost.new.domain_with_port) %>",
plugins: {
core: [ClapprMarkersPlugin]
},
markersPlugin: {},
width: '100%',
height: '100%',
mute: true,
autoPlay: true,
hlsMinimumDvrSize: 1
});
markerData.forEach(function(marker, index) {
var markers = player.getPlugin("markers-plugin");
var marker = new ClapprMarkersPlugin.StandardMarker(Number(marker.table.time_elapsed), marker.table.note)
markers.addMarker(marker);
});
<% end %>
<% end %>
</div>
</div>
</div>
</div>
<div class="col-lg-4 col-md-12 mb-3">
<div class="card shadow-sm mb-3">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<li class="nav-item">
<%= link_to "Home", "#home", class: class_string("nav-link", "active" => !params[:active_tab].present?), data: { toggle: "tab" } %>
</li>
<li class="nav-item">
<%= link_to "Files", "#files", class: class_string("nav-link", "active" => params[:active_tab] == "files"), data: { toggle: "tab" } %>
</li>
</ul>
</div>
<div class="card-body p-3">
<div class="tab-content">
<div class="<%= class_string("tab-pane fade show", "active" => !params[:active_tab].present?) %>" id="home">
<div class="row">
<div class="col-md-12">
<dl>
<%= description_list_pair_for @casting_call, :title, append: ":" %>
<%= description_list_pair_for @casting_call, :status, append: ":" %>
<%= description_list_pair_for @casting_call, :created_at, append: ":" %>
<%= description_list_pair_for @casting_call, :description, append: ":" %>
<%= description_list_pair_for @casting_call, :project_description, append: ":" %>
<%= description_list_pair_for @casting_call, :interview_instructions, append: ":" %>
<%= description_list_pair_for @casting_call, :interview_requirements, append: ":" %>
<%= description_list_pair_for @casting_call, :questions, append: ":" %>
</dl>
</div>
</div>
</div>
<div class="<%= class_string("tab-pane fade show", "active" => params[:active_tab] == 'files') %>" id="files">
<div class="tab-pane fade show active" id="files_casting_submission_<%= @casting_submission.id %>">
<%= render partial: 'casting_submissions/files_section', locals: { casting_submission: @casting_submission, files: @files } %>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -21,9 +21,9 @@
<%= link_to t("projects.show.tasks"), [@project, :tasks], class: "text-decoration-none text-reset stretched-link" %>
<% end %>
<% end %>
<% if policy(Project).show_casting_call_interview_results? %>
<% if policy(Project).show_casting_submission_results? %>
<%= render "folder_card" do %>
<%= link_to t("projects.show.casting_call_interviews"), [@project, :casting_call_interviews], class: "text-decoration-none text-reset stretched-link" %>
<%= link_to t("projects.show.casting_submissions"), [@project, :casting_submissions], class: "text-decoration-none text-reset stretched-link" %>
<% end %>
<% end %>
</div>

View File

@@ -12,20 +12,11 @@
<%= card_header text: @casting_call.title %>
<div class="card-body">
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="col-12">
<dl>
<%= description_list_pair_for @casting_call, :title, append: ":" %>
<%= description_list_pair_for @casting_call, :description, append: ":" %>
<%= description_list_pair_for @casting_call, :project_description, append: ":" %>
<%= description_list_pair_for @casting_call, :created_at, append: ":" %>
</dl>
</div>
<div class="col-md-6 col-sm-12">
<dl>
<%= description_list_pair_for @casting_call, :status, append: ":" %>
<%= description_list_pair_for @casting_call, :interview_instructions, append: ":" %>
<%= description_list_pair_for @casting_call, :interview_requirements, append: ":" %>
<%= description_list_pair_for @casting_call, :questions, append: ":" %>
</dl>
</div>
</div>

View File

@@ -1,11 +1,11 @@
<div class="card shadow-sm">
<%= card_header text: "Casting call interview details" %>
<%= card_header text: "Casting submission details" %>
<div class="card-body">
<div class="row">
<div class="col-lg-12">
<dl>
<%= description_list_pair_for @casting_call_interview, :performer_name, append: ":" %>
<%= description_list_pair_for @casting_call_interview, :interview_date, append: ":" %>
<%= description_list_pair_for @casting_submission, :performer_name, append: ":" %>
<%= description_list_pair_for @casting_submission, :interview_date, append: ":" %>
</dl>
</div>
</div>
@@ -16,14 +16,14 @@
<div class="card shadow-sm">
<%= card_header text: t(".heading") %>
<div class="card-body">
<%= errors_summary_for @casting_call_interview %>
<%= bootstrap_form_with model: @casting_call_interview, url: casting_call_interview_path(token: @casting_call_interview.token), local: true do |form| %>
<%= errors_summary_for @casting_submission %>
<%= bootstrap_form_with model: @casting_submission, url: casting_submission_path(token: @casting_submission.token), local: true do |form| %>
<div class="field d-none">
<%= form.label :files %>
<%= form.file_field :files, disable: true, direct_upload: true, multiple: true, id: "casting_call_interivew_files", hide_label: true %>
<% @casting_call_interview.files.each do |file| %>
<% @casting_submission.files.each do |file| %>
<% unless file.persisted? %>
<%= hidden_field_tag "#{@casting_call_interview.model_name.param_key}[files][]", file.signed_id %>
<%= hidden_field_tag "#{@casting_submission.model_name.param_key}[files][]", file.signed_id %>
<% end %>
<% end %>
</div>
@@ -32,8 +32,8 @@
data-accepted-files="audio/*,image/*,video/*"
data-behavior="dropzone"
data-file-input-id="casting_call_interivew_files"
data-existing-files="<%= mock_photos_json(@casting_call_interview.files) %>"
data-placeholder="<%= dropzone_placeholder_message_for(@casting_call_interview) %>"
data-existing-files="<%= mock_photos_json(@casting_submission.files) %>"
data-placeholder="<%= dropzone_placeholder_message_for(@casting_submission) %>"
data-submit-button="#submit_folder"></div>
<div class="mt-5">
@@ -45,7 +45,7 @@
</div>
</div>
<div class="row align-items-center justify-content-center mt-3">
<%= link_to "Start Interview", @casting_call_interview.join_zoom_meeting_url, target: "_blank", class: "btn btn-primary" %>
<%= link_to "Start Interview", @casting_submission.zoom_meeting_url, target: "_blank", class: "btn btn-primary" %>
</div>
</div>
</div>

View File

@@ -70,6 +70,9 @@ en:
person_phone: Phone
person_photo: Photo
signed_on: Date
casting_call:
interview_instructions: Welcome message
interview_requirements: Goodbye message
location_release:
person_company: Company
person_email: Email
@@ -97,22 +100,25 @@ en:
application:
header:
sign_out: Sign Out
casting_call_interviews:
casting_submissions:
complete:
notice: The casting call interview has been completed
notice: The casting submission has been completed
create:
notice: The casting call interview has been created
notice: The casting submission has been created
form:
casting_submission_markers:
heading: Markers
index:
actions:
new: Create Casting Call Interview
empty: Casting call interviews will appear here
new: Create Casting Submission
empty: Casting submissions will appear here
mark_as_completed:
alert: Failed to mark casting call interview as completed
notice: The casting call interview has been marked as completed
alert: Failed to mark casting submission as completed
notice: The casting submission has been marked as completed
new:
heading: New Casting Call Interview
heading: New Casting Submission
update:
notice: The casting call interview has been updated
notice: The casting submission has been updated
task_requests:
index:
empty: Task requests will appear here
@@ -244,11 +250,6 @@ en:
bulk_taggings:
new_bulk_tag_modal:
submit: Add
casting_call_interviews:
index:
empty: Casting Call Interview results will appear here.
show:
empty: Interview files and recorded meeetings will appear here.
casting_calls:
cancel:
notice: The casting call request has been cancelled successfully
@@ -256,19 +257,13 @@ en:
actions:
manage: Manage
create:
notice: The casting call request has been created
success_message: Your casting call request was successfully submitted. Thank you. A chat window will pop up on the lower right in a few seconds.
notice: The casting call request has been created successfully.
edit:
heading: Edit Casting Call
form:
headings:
chatbot: Chatbot Instructions
info_message: After submitting this casting call request, you'll be connected via chat with a ME Suite representative.
labels:
description: Description
interview_instructions: Interview instructions
interview_requirements: Interview requirements
project_description: Project description
questions: Questions
title: Title
index:
actions:
new: Create Casting Call
@@ -276,11 +271,38 @@ en:
table_headers:
casting_call_created_on: Created On
casting_call_status: Status
casting_call_title: Title
casting_call_title: Casting Title
new:
heading: New Casting Call
splash:
actions:
book_demo: Schedule a Demo
create_casting_call: Create Casting Call
headings:
benefits: Benefits
how_it_works: How It Works
subtitle: The media industry's first automated casting bot
welcome: Welcome to
list_items:
copy_and_paste_submission_link: Copy and paste the submission link wherever you want
enter_information: Enter information about the role and project
enter_questions: Enter the questions you want the Chatbot to ask
fewer_resources_needed: Fewer resources needed for first round of casting search
fewer_team_members_needed: Fewer team members needed to cast large projects
more_time_spent_with_quality_candidates: More time spent with quality casting candidates
wait_for_the_submission_video: Wait for the casting bot to deliver you casting submission videos
update:
notice: The casting call request has been updated
casting_submission_downloads:
download:
failure: Your download could not be generated.
pending: "Your %{release_type} files are being prepared for download. You will be notified when it's ready."
success: "Your %{release_type} files are ready. Download now, or retrieve later in the %{downloads_folder_link} folder. %{download_button}"
casting_submissions:
index:
empty: Casting Submission results will appear here.
show:
empty: Casting Submission files and recorded meeetings will appear here.
contract_downloads:
download:
failure: Your download could not be generated.
@@ -414,6 +436,10 @@ en:
notice: The release has been updated
helpers:
help:
casting_call:
interview_instructions: This is the first message the chatbot, BiGGiE, will send. Please include all information and instructions you wish the person to read prior to starting the casting interview.
interview_requirements: Please enter a final message and include any post-interview instructions (for example, submitting a headshot, additional photos, videos, etc).
questions: Please list, one-by-one, all of the questions you wish the chatbot, BiGGiE, to ask the person.
contract_template:
fee: Leave at $0.00 for no-fee
guardian_clause: Leave blank if not required for this contract
@@ -472,6 +498,13 @@ en:
person_last_name: Last name
person_name: Name
person_phone: Phone number
casting_call:
description: Casting search description
interview_instructions: Welcome message
interview_requirements: Goodbye message
project_description: Project description
questions: Questions
title: Casting search title
location_release:
address_city: City
address_country: Country
@@ -721,6 +754,8 @@ en:
broadcast:
create: Create Live Stream
update: Save Changes
casting_submission:
create: Create Casting Submission
contract_template:
create: Create Release Template
directory:
@@ -753,11 +788,6 @@ en:
cards: Cards
heading: Import Releases
list: List
interview_downloads:
download:
failure: Your download could not be generated.
pending: "Your %{release_type} files are being prepared for download. You will be notified when it's ready."
success: "Your %{release_type} files are ready. Download now, or retrieve later in the %{downloads_folder_link} folder. %{download_button}"
location_releases:
create:
notice: The location release has been created
@@ -989,7 +1019,7 @@ en:
show:
acquired_media_release: Acquired Media Releases (%{count})
appearance_release: Appearance Releases (%{count})
casting_call_interviews: Interviews
casting_submissions: Casting Submissions
downloads: Downloads
location_release: Location Releases (%{count})
material_release: Material Releases (%{count})
@@ -1052,7 +1082,7 @@ en:
broadcasts:
show:
alert: That broadcast is no longer available
casting_call_interviews:
casting_submissions:
show:
heading: Files
update: Upload

View File

@@ -76,6 +76,26 @@ es:
share_stream: Share live stream link with clients
stream_from_mobile_app: Stream from ME Suite Mobile app, or via a professional camera
stream_multiple_cameras: Stream multiple cameras at one time
casting_calls:
index:
empty: Casting calls will appear here (ES)
splash:
actions:
book_demo: Schedule a Demo (ES)
create_casting_call: Create Casting Call (ES)
headings:
benefits: Benefits (ES)
how_it_works: How It Works (ES)
subtitle: The media industry's first automated casting bot (ES)
welcome: Welcome to (ES)
list_items:
copy_and_paste_submission_link: Copy and paste the submission link wherever you want (ES)
enter_information: Enter information about the role and project (ES)
enter_questions: Enter the questions you want the Chatbot to ask (ES)
fewer_resources_needed: Fewer resources needed for first round of casting search (ES)
fewer_team_members_needed: Fewer team members needed to cast large projects (ES)
more_time_spent_with_quality_candidates: More time spent with quality casting candidates (ES)
wait_for_the_submission_video: Wait for the casting bot to deliver you casting submission videos (ES)
contract_templates:
blank_contracts:
create:
@@ -272,6 +292,8 @@ es:
broadcast:
create: Create Live Stream (ES)
update: Save Changes (ES)
casting_submission:
create: Create casting submission (ES)
create: 'Crear %{model}'
update: 'Actualizar %{model}'
location_releases:

View File

@@ -32,7 +32,7 @@ Rails.application.routes.draw do
resource :masquerade, only: :create
end
resources :task_requests, only: [:index, :edit, :update, :show]
resources :casting_call_interviews do
resources :casting_submissions do
post :complete, on: :member
end
@@ -69,7 +69,7 @@ Rails.application.routes.draw do
resource :contract_downloads, only: [:create]
resources :downloads, only: [:index, :destroy]
resource :report_downloads, only: [:create]
resource :interview_downloads, only: [:create]
resource :casting_submission_downloads, only: [:create]
resources :videos, only: [:index, :new, :create, :edit, :update] do
collection do
get :landing
@@ -115,7 +115,7 @@ Rails.application.routes.draw do
end
end
resources :tasks, only: :index
resources :casting_call_interviews, only: [:index, :show]
resources :casting_submissions, only: [:index, :show]
end
resource :profile, only: [:show, :update]
resources :videos, only: [] do
@@ -145,7 +145,7 @@ Rails.application.routes.draw do
resource :zoom_meeting, only: [:show]
end
resources :casting_calls, param: :token, only: [:show]
resources :casting_call_interviews, param: :token, only: [:show, :update]
resources :casting_submissions, param: :token, only: [:show, :update]
end
RELEASES = [:acquired_media_releases, :appearance_releases, :talent_releases, :material_releases, :location_releases]

View File

@@ -0,0 +1,5 @@
class RenameCastingCallInterviewsToCastingSubmissions < ActiveRecord::Migration[6.0]
def change
rename_table :casting_call_interviews, :casting_submissions
end
end

View File

@@ -0,0 +1,35 @@
class AddMarkersToCastingSubmissions < ActiveRecord::Migration[6.0]
def change
add_column :casting_submissions, :time_elapsed_1, :integer
add_column :casting_submissions, :time_elapsed_2, :integer
add_column :casting_submissions, :time_elapsed_3, :integer
add_column :casting_submissions, :time_elapsed_4, :integer
add_column :casting_submissions, :time_elapsed_5, :integer
add_column :casting_submissions, :time_elapsed_6, :integer
add_column :casting_submissions, :time_elapsed_7, :integer
add_column :casting_submissions, :time_elapsed_8, :integer
add_column :casting_submissions, :time_elapsed_9, :integer
add_column :casting_submissions, :time_elapsed_10, :integer
add_column :casting_submissions, :time_elapsed_11, :integer
add_column :casting_submissions, :time_elapsed_12, :integer
add_column :casting_submissions, :time_elapsed_13, :integer
add_column :casting_submissions, :time_elapsed_14, :integer
add_column :casting_submissions, :time_elapsed_15, :integer
add_column :casting_submissions, :note_1, :text
add_column :casting_submissions, :note_2, :text
add_column :casting_submissions, :note_3, :text
add_column :casting_submissions, :note_4, :text
add_column :casting_submissions, :note_5, :text
add_column :casting_submissions, :note_6, :text
add_column :casting_submissions, :note_7, :text
add_column :casting_submissions, :note_8, :text
add_column :casting_submissions, :note_9, :text
add_column :casting_submissions, :note_10, :text
add_column :casting_submissions, :note_11, :text
add_column :casting_submissions, :note_12, :text
add_column :casting_submissions, :note_13, :text
add_column :casting_submissions, :note_14, :text
add_column :casting_submissions, :note_15, :text
end
end

View File

@@ -331,8 +331,8 @@ CREATE TABLE public.appearance_releases (
person_last_name character varying,
guardian_first_name character varying,
guardian_last_name character varying,
identifier character varying,
guardian_email character varying,
identifier character varying,
person_address_street2 character varying,
person_address_city character varying,
person_address_state character varying,
@@ -569,42 +569,6 @@ CREATE SEQUENCE public.broadcasts_id_seq
ALTER SEQUENCE public.broadcasts_id_seq OWNED BY public.broadcasts.id;
--
-- Name: casting_call_interviews; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.casting_call_interviews (
id bigint NOT NULL,
casting_call_id bigint,
performer_name character varying,
zoom_meeting_url character varying,
interview_date timestamp without time zone,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
token character varying,
interviewed_at timestamp without time zone
);
--
-- Name: casting_call_interviews_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.casting_call_interviews_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: casting_call_interviews_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.casting_call_interviews_id_seq OWNED BY public.casting_call_interviews.id;
--
-- Name: casting_calls; Type: TABLE; Schema: public; Owner: -
--
@@ -645,6 +609,72 @@ CREATE SEQUENCE public.casting_calls_id_seq
ALTER SEQUENCE public.casting_calls_id_seq OWNED BY public.casting_calls.id;
--
-- Name: casting_submissions; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.casting_submissions (
id bigint NOT NULL,
casting_call_id bigint,
performer_name character varying,
zoom_meeting_url character varying,
interview_date timestamp without time zone,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
token character varying,
interviewed_at timestamp without time zone,
time_elapsed_1 integer,
time_elapsed_2 integer,
time_elapsed_3 integer,
time_elapsed_4 integer,
time_elapsed_5 integer,
time_elapsed_6 integer,
time_elapsed_7 integer,
time_elapsed_8 integer,
time_elapsed_9 integer,
time_elapsed_10 integer,
time_elapsed_11 integer,
time_elapsed_12 integer,
time_elapsed_13 integer,
time_elapsed_14 integer,
time_elapsed_15 integer,
note_1 text,
note_2 text,
note_3 text,
note_4 text,
note_5 text,
note_6 text,
note_7 text,
note_8 text,
note_9 text,
note_10 text,
note_11 text,
note_12 text,
note_13 text,
note_14 text,
note_15 text
);
--
-- Name: casting_submissions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.casting_submissions_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: casting_submissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.casting_submissions_id_seq OWNED BY public.casting_submissions.id;
--
-- Name: composers; Type: TABLE; Schema: public; Owner: -
--
@@ -742,6 +772,15 @@ 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: -
--
@@ -1483,7 +1522,6 @@ CREATE TABLE public.settings (
--
CREATE SEQUENCE public.settings_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1519,7 +1557,6 @@ CREATE TABLE public.taggings (
--
CREATE SEQUENCE public.taggings_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1550,7 +1587,6 @@ CREATE TABLE public.tags (
--
CREATE SEQUENCE public.tags_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1911,9 +1947,9 @@ CREATE TABLE public.zoom_meetings (
api_meeting_id character varying,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
status integer DEFAULT 0,
zoom_user_id bigint,
project_id bigint,
status integer DEFAULT 0
project_id bigint
);
@@ -2053,13 +2089,6 @@ ALTER TABLE ONLY public.broadcast_recordings ALTER COLUMN id SET DEFAULT nextval
ALTER TABLE ONLY public.broadcasts ALTER COLUMN id SET DEFAULT nextval('public.broadcasts_id_seq'::regclass);
--
-- Name: casting_call_interviews id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.casting_call_interviews ALTER COLUMN id SET DEFAULT nextval('public.casting_call_interviews_id_seq'::regclass);
--
-- Name: casting_calls id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -2067,6 +2096,13 @@ ALTER TABLE ONLY public.casting_call_interviews ALTER COLUMN id SET DEFAULT next
ALTER TABLE ONLY public.casting_calls ALTER COLUMN id SET DEFAULT nextval('public.casting_calls_id_seq'::regclass);
--
-- Name: casting_submissions id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.casting_submissions ALTER COLUMN id SET DEFAULT nextval('public.casting_submissions_id_seq'::regclass);
--
-- Name: composers id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -2388,14 +2424,6 @@ ALTER TABLE ONLY public.broadcasts
ADD CONSTRAINT broadcasts_pkey PRIMARY KEY (id);
--
-- Name: casting_call_interviews casting_call_interviews_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.casting_call_interviews
ADD CONSTRAINT casting_call_interviews_pkey PRIMARY KEY (id);
--
-- Name: casting_calls casting_calls_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2404,6 +2432,14 @@ ALTER TABLE ONLY public.casting_calls
ADD CONSTRAINT casting_calls_pkey PRIMARY KEY (id);
--
-- Name: casting_submissions casting_submissions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.casting_submissions
ADD CONSTRAINT casting_submissions_pkey PRIMARY KEY (id);
--
-- Name: composers composers_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2420,6 +2456,14 @@ 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: -
--
@@ -2821,20 +2865,6 @@ CREATE INDEX index_broadcasts_on_project_id ON public.broadcasts USING btree (pr
CREATE UNIQUE INDEX index_broadcasts_on_token ON public.broadcasts USING btree (token);
--
-- Name: index_casting_call_interviews_on_casting_call_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_casting_call_interviews_on_casting_call_id ON public.casting_call_interviews USING btree (casting_call_id);
--
-- Name: index_casting_call_interviews_on_token; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_casting_call_interviews_on_token ON public.casting_call_interviews USING btree (token);
--
-- Name: index_casting_calls_on_project_id; Type: INDEX; Schema: public; Owner: -
--
@@ -2849,6 +2879,20 @@ CREATE INDEX index_casting_calls_on_project_id ON public.casting_calls USING btr
CREATE UNIQUE INDEX index_casting_calls_on_token ON public.casting_calls USING btree (token);
--
-- Name: index_casting_submissions_on_casting_call_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_casting_submissions_on_casting_call_id ON public.casting_submissions USING btree (casting_call_id);
--
-- Name: index_casting_submissions_on_token; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX index_casting_submissions_on_token ON public.casting_submissions USING btree (token);
--
-- Name: index_composers_on_music_release_id; Type: INDEX; Schema: public; Owner: -
--
@@ -3447,10 +3491,10 @@ ALTER TABLE ONLY public.bookmarks
--
-- Name: casting_call_interviews fk_rails_1583f69fbb; Type: FK CONSTRAINT; Schema: public; Owner: -
-- Name: casting_submissions fk_rails_1583f69fbb; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.casting_call_interviews
ALTER TABLE ONLY public.casting_submissions
ADD CONSTRAINT fk_rails_1583f69fbb FOREIGN KEY (casting_call_id) REFERENCES public.casting_calls(id);
@@ -4063,6 +4107,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200702152130'),
('20200706193123'),
('20200706230803'),
('20200707070522');
('20200707070522'),
('20200714175331'),
('20200722193459');

View File

@@ -1,106 +0,0 @@
require "rails_helper"
RSpec.describe Admin::CastingCallInterviewsController, type: :controller do
let!(:current_user) { create(:user, :admin) }
before do
sign_in(current_user)
end
describe "#index" do
it "returns a successful response" do
get :index
expect(response).to be_successful
end
end
describe "#new" do
it "returns a successful response" do
get :new
expect(response).to be_successful
end
it "assigns user, accounts" do
get :new
expect(assigns(:casting_call_interview)).not_to be_nil
expect(assigns(:accounts)).to eq Account.all
end
end
describe "#create" do
it "does create a new record" do
expect {
post :create, params: { casting_call_interview: casting_call_interview_params }
}.to change(CastingCallInterview, :count)
end
end
describe "#edit" do
let(:casting_call_interview) { create(:casting_call_interview) }
it "returns a successful response" do
get :edit, params: { id: casting_call_interview }
expect(response).to be_successful
end
it "assigns casting call interview" do
get :edit, params: { id: casting_call_interview }
expect(assigns(:casting_call_interview)).to eq casting_call_interview
end
end
describe "#update" do
let(:casting_call_interview) { create(:casting_call_interview) }
it "redirects to casting call interviews page" do
patch :update, params: { id: casting_call_interview, casting_call_interview: update_params }
expect(response).to be_redirect
expect(response).to redirect_to admin_casting_call_interviews_path
end
it "sets a flash notice" do
patch :update, params: { id: casting_call_interview, casting_call_interview: update_params }
expect(flash.notice).to eq "The casting call interview has been updated"
end
it "updates casting call interview" do
patch :update, params: { id: casting_call_interview, casting_call_interview: update_params }
expect(casting_call_interview.reload.zoom_meeting_url).to eq("new_zoom_meeting_url")
end
end
describe "#complete" do
let(:casting_call_interview) { create(:casting_call_interview) }
it "sets interviewed_at on casting call interview" do
expect(casting_call_interview.interviewed_at).to be_nil
post :complete, params: { id: casting_call_interview }
expect(casting_call_interview.reload.interviewed_at).not_to be_nil
end
end
private
def casting_call_interview_params
casting_call = create(:casting_call)
attributes_for(:casting_call_interview).except(:interviewed_at).merge(casting_call_id: casting_call.id)
end
def update_params
{
zoom_meeting_url: "new_zoom_meeting_url"
}
end
end

View File

@@ -0,0 +1,114 @@
require "rails_helper"
RSpec.describe Admin::CastingSubmissionsController, type: :controller do
let!(:current_user) { create(:user, :admin) }
before do
sign_in(current_user)
end
describe "#index" do
it "returns a successful response" do
get :index
expect(response).to be_successful
end
end
describe "#new" do
it "returns a successful response" do
get :new
expect(response).to be_successful
end
it "assigns user, accounts" do
get :new
expect(assigns(:casting_submission)).not_to be_nil
expect(assigns(:accounts)).to eq Account.all
end
end
describe "#create" do
it "does create a new record" do
expect {
post :create, params: { casting_submission: casting_submission_params }
}.to change(CastingSubmission, :count)
end
end
describe "#edit" do
let(:casting_submission) { create(:casting_submission) }
it "returns a successful response" do
get :edit, params: { id: casting_submission }
expect(response).to be_successful
end
it "assigns casting submission" do
get :edit, params: { id: casting_submission }
expect(assigns(:casting_submission)).to eq casting_submission
end
end
describe "#update" do
let(:casting_submission) { create(:casting_submission) }
it "redirects to casting submissions page" do
patch :update, params: { id: casting_submission, casting_submission: update_params }
expect(response).to be_redirect
expect(response).to redirect_to admin_casting_submissions_path
end
it "sets a flash notice" do
patch :update, params: { id: casting_submission, casting_submission: update_params }
expect(flash.notice).to eq "The casting submission has been updated"
end
it "updates casting submission" do
patch :update, params: { id: casting_submission, casting_submission: update_params }
expect(casting_submission.reload.zoom_meeting_url).to eq new_zoom_meeting_url
end
end
describe "#complete" do
let(:casting_submission) { create(:casting_submission) }
it "sets interviewed_at on casting submission" do
expect(casting_submission.interviewed_at).to be_nil
post :complete, params: { id: casting_submission }
expect(casting_submission.reload.interviewed_at).not_to be_nil
end
end
private
def casting_submission_params
casting_call = create(:casting_call)
attributes_for(:casting_submission).except(:interviewed_at).merge(casting_call_id: casting_call.id)
end
def update_params
{
zoom_meeting_url: new_zoom_meeting_url
}
end
def new_zoom_meeting_url
"https://s01web.zoom.us/j/11111?pwd=Ab123Cq34"
end
def invalid_meeting_url_flash_error
t 'casting_submissions.validation_errors.invalid_meeting_url'
end
end

View File

@@ -1,43 +0,0 @@
require "rails_helper"
RSpec.describe CastingCallInterviewsController, type: :controller do
render_views
let(:user) { create(:user) }
let(:account) { user.primary_account }
let(:project) { create(:project, account: user.primary_account) }
let(:casting_call) { create(:casting_call, project: project, title: "My Interview") }
before do
sign_in(user)
end
describe "#index" do
it "returns a successful response" do
get :index, params: { project_id: project }
expect(response).to be_successful
end
it "only shows completed interviews" do
create(:casting_call_interview, casting_call: casting_call, interviewed_at: Time.zone.now, performer_name: "John Doe")
create(:casting_call_interview, casting_call: casting_call, interviewed_at: nil, performer_name: "Jane Doe")
get :index, params: { project_id: project }
expect(response.body).to have_content("John Doe")
expect(response.body).not_to have_content("Jane Doe")
end
end
describe "#show" do
let!(:casting_call_interview) { create(:casting_call_interview, :with_files, casting_call: casting_call, interviewed_at: Time.zone.now, performer_name: "Jane Doe") }
it "shows files of casting call interview" do
get :show, params: { project_id: project, id: casting_call_interview.id }
expect(response.body).to have_content("Filename")
expect(response.body).to have_content("location_photo.png")
end
end
end

View File

@@ -18,7 +18,7 @@ RSpec.describe CastingCallsController, type: :controller do
expect(response).to be_successful
end
it "renders content" do
it "renders content if there are existing broadcasts" do
create(:casting_call, project: project)
get :index, params: { project_id: project }
@@ -36,6 +36,18 @@ RSpec.describe CastingCallsController, type: :controller do
expect(response.body).to have_link("2", href: project_casting_calls_path(project, page: 2))
end
end
context "when there are no records" do
it "renders splash screen" do
CastingCall.destroy_all
get :index, params: { project_id: project }
expect(response.body).not_to have_content no_casting_calls_message
expect(response.body).to have_link create_casting_call
expect(response.body).to have_link schedule_demo
end
end
end
describe "#new" do
@@ -60,12 +72,6 @@ RSpec.describe CastingCallsController, type: :controller do
post :create, params: { project_id: project.id, casting_call: casting_call_params }
}.to have_enqueued_job(TrackAnalyticsJob).with(user, account, :track_create_casting_call, user_agent: "Rails Testing", user_ip: "0.0.0.0")
end
it "submits data to hubspot form" do
expect {
post :create, params: { project_id: project.id, casting_call: casting_call_params }
}.to have_enqueued_job(SubmitHubspotFormJob)
end
end
describe "#update" do
@@ -123,4 +129,16 @@ RSpec.describe CastingCallsController, type: :controller do
def update_params
{ description: "This is updated description" }
end
def no_casting_calls_message
t 'casting_calls.index.empty'
end
def create_casting_call
t 'casting_calls.splash.actions.create_casting_call'
end
def schedule_demo
t 'casting_calls.splash.actions.book_demo'
end
end

View File

@@ -1,12 +1,12 @@
require "rails_helper"
RSpec.describe InterviewDownloadsController, type: :controller do
RSpec.describe CastingSubmissionDownloadsController, type: :controller do
render_views
let(:current_user) { create(:user) }
let(:project) { create(:project, :discovery_client, account: current_user.primary_account) }
let(:casting_call) { create(:casting_call, project: project, title: "My Title") }
let(:casting_call_interview) { create(:casting_call_interview, casting_call: casting_call, performer_name: "John Doe") }
let(:casting_submission) { create(:casting_submission, casting_call: casting_call, performer_name: "John Doe") }
before do
sign_in current_user
@@ -15,13 +15,13 @@ RSpec.describe InterviewDownloadsController, type: :controller do
describe "#create" do
it "enqueues zip file generation job" do
expect {
post :create, params: { project_id: project.id, casting_call_interview_id: casting_call_interview.id }, format: :js
}.to have_enqueued_job(GenerateInterviewFilesZipJob)
post :create, params: { project_id: project.id, casting_submission_id: casting_submission.id }, format: :js
}.to have_enqueued_job(GenerateCastingSubmissionFilesZipJob)
end
it "creates a download record with 'not_started' status" do
expect {
post :create, params: { project_id: project.id, casting_call_interview_id: casting_call_interview.id }, format: :js
post :create, params: { project_id: project.id, casting_submission_id: casting_submission.id }, format: :js
}.to change(Download, :count).by(1)
expect(Download.last.status).to eq('not_started')
@@ -29,11 +29,11 @@ RSpec.describe InterviewDownloadsController, type: :controller do
context "When there is no existing job" do
it "shows a notification to user" do
allow(ProjectsChannel).to receive(:broadcast_download_generation_update).with(be_kind_of(Download), I18n.t("interview_downloads.download.pending", release_type: "Casting Call Interview"))
allow(ProjectsChannel).to receive(:broadcast_download_generation_update).with(be_kind_of(Download), I18n.t("casting_submission_downloads.download.pending", release_type: "CastingSubmission"))
post :create, params: { project_id: project.id, casting_call_interview_id: casting_call_interview.id }, format: :js
post :create, params: { project_id: project.id, casting_submission_id: casting_submission.id }, format: :js
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(be_kind_of(Download), I18n.t("interview_downloads.download.pending", release_type: "Casting Call Interview"))
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(be_kind_of(Download), I18n.t("casting_submission_downloads.download.pending", release_type: "CastingSubmission"))
end
end
@@ -47,9 +47,9 @@ RSpec.describe InterviewDownloadsController, type: :controller do
end
it "shows names of other contracts in the notification, which are in progress" do
broadcast_message = "<p>Your Casting Call Interview files are being prepared for download. You will be notified when it's ready.\n</p>\n<p class=\"mt-3\">The following downloads are also in progress:</p> \n<ul>\n <li>Acquired Media Release contracts (as of less than a minute ago)\n </li>\n <li>Appearance Release contracts (as of less than a minute ago)\n </li>\n</ul>\n"
broadcast_message = "<p>Your Casting Submission files are being prepared for download. You will be notified when it's ready.\n</p>\n<p class=\"mt-3\">The following downloads are also in progress:</p> \n<ul>\n <li>Acquired Media Release contracts (as of less than a minute ago)\n </li>\n <li>Appearance Release contracts (as of less than a minute ago)\n </li>\n</ul>\n"
post :create, params: { project_id: project.id, casting_call_interview_id: casting_call_interview.id }, format: :js
post :create, params: { project_id: project.id, casting_submission_id: casting_submission.id }, format: :js
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(be_kind_of(Download), broadcast_message)
end

View File

@@ -0,0 +1,44 @@
require "rails_helper"
RSpec.describe CastingSubmissionsController, type: :controller do
render_views
let(:user) { create(:user) }
let(:account) { user.primary_account }
let(:project) { create(:project, account: user.primary_account) }
let(:casting_call) { create(:casting_call, project: project, title: "My Interview") }
before do
sign_in(user)
end
describe "#index" do
it "returns a successful response" do
get :index, params: { project_id: project }
expect(response).to be_successful
end
it "only shows completed submissions" do
create(:casting_submission, casting_call: casting_call, interviewed_at: Time.zone.now, performer_name: "John Doe")
create(:casting_submission, casting_call: casting_call, interviewed_at: nil, performer_name: "Jane Doe")
get :index, params: { project_id: project }
expect(response.body).to have_content("John Doe")
expect(response.body).not_to have_content("Jane Doe")
end
end
describe "#show" do
let!(:casting_submission) { create(:casting_submission, :with_files, casting_call: casting_call, interviewed_at: Time.zone.now, performer_name: "Jane Doe") }
it "shows files of casting submission" do
get :show, params: { project_id: project, id: casting_submission.id }
expect(response.body).to have_content(casting_submission.performer_name)
expect(response.body).to have_content(casting_submission.casting_call.title)
expect(response.body).to have_content(casting_submission.casting_call.project_description)
end
end
end

View File

@@ -1,44 +0,0 @@
require 'rails_helper'
RSpec.describe Public::CastingCallInterviewsController, type: :controller do
render_views
describe "#show" do
let(:casting_call_interview) { create(:casting_call_interview) }
it "responds successfully" do
get :show, params: { token: casting_call_interview.token }
expect(response).to be_successful
expect(assigns(:casting_call_interview)).to eq(casting_call_interview)
end
it "shows casting call interview details" do
get :show, params: { token: casting_call_interview.token }
expect(response.body).to have_content(casting_call_interview.performer_name)
expect(response.body).to have_content(casting_call_interview.interview_date)
expect(response.body).to have_link("Start Interview")
end
end
describe "#update" do
let(:casting_call_interview) { create(:casting_call_interview) }
it "responds successfully" do
patch :update, params: { token: casting_call_interview.token, casting_call_interview: casting_call_interview_params }
expect(response).to redirect_to casting_call_interview_url(token: casting_call_interview.token)
expect(flash.notice).to be_present
end
end
private
def casting_call_interview_params
path = Rails.root.join("spec", "fixtures", "files", "contract.pdf")
file = Rack::Test::UploadedFile.new(path, "application/pdf")
{ files: [file]}
end
end

View File

@@ -19,9 +19,6 @@ RSpec.describe Public::CastingCallsController, type: :controller do
expect(response.body).to have_content(casting_call.title)
expect(response.body).to have_content(casting_call.description)
expect(response.body).to have_content(casting_call.project_description)
expect(response.body).to have_content(casting_call.interview_instructions)
expect(response.body).to have_content(casting_call.interview_requirements)
expect(response.body).to have_content(casting_call.questions)
expect(response.body).to have_link("Schedule an Audition")
end
end

View File

@@ -0,0 +1,44 @@
require 'rails_helper'
RSpec.describe Public::CastingSubmissionsController, type: :controller do
render_views
describe "#show" do
let(:casting_submission) { create(:casting_submission) }
it "responds successfully" do
get :show, params: { token: casting_submission.token }
expect(response).to be_successful
expect(assigns(:casting_submission)).to eq(casting_submission)
end
it "shows casting call interview details" do
get :show, params: { token: casting_submission.token }
expect(response.body).to have_content(casting_submission.performer_name)
expect(response.body).to have_content(casting_submission.interview_date)
expect(response.body).to have_link("Start Interview")
end
end
describe "#update" do
let(:casting_submission) { create(:casting_submission) }
it "responds successfully" do
patch :update, params: { token: casting_submission.token, casting_submission: casting_submission_params }
expect(response).to redirect_to casting_submission_url(token: casting_submission.token)
expect(flash.notice).to be_present
end
end
private
def casting_submission_params
path = Rails.root.join("spec", "fixtures", "files", "contract.pdf")
file = Rack::Test::UploadedFile.new(path, "application/pdf")
{ files: [file]}
end
end

View File

@@ -2,6 +2,7 @@ FactoryBot.define do
factory :casting_call do
association :project
user_email 'test@email.com'
title 'Casting Call Title'
description "Casting call description"
project_description "Casting call project description"
interview_instructions "Interview instructions"

View File

@@ -1,5 +1,5 @@
FactoryBot.define do
factory :casting_call_interview do
factory :casting_submission do
association :casting_call
performer_name 'John Doe'
zoom_meeting_url 'https://us04web.zoom.us/j/1111111111?pwd=aDZCS1dzZ2lWdDZJcHBhVnNIclB4QT03'
@@ -9,5 +9,9 @@ FactoryBot.define do
trait :with_files do
files { [Rack::Test::UploadedFile.new('spec/fixtures/files/location_photo.png', 'image/png')] }
end
trait :with_interview_recording do
interview_recording { Rack::Test::UploadedFile.new('spec/fixtures/files/video_file.mp4', 'video/mp4') }
end
end
end

View File

@@ -0,0 +1,140 @@
require "rails_helper"
feature "Admin managing casting submissions" do
let(:current_user) { create(:user, admin: true, email: "user@test.com") }
let(:project) { create(:project, account: current_user.primary_account, name: "Test Project") }
before do
sign_in current_user
end
scenario "when creating new casting call interview - interview recording field is not visible" do
visit admin_casting_submissions_path
click_on create_casting_submission_button
expect(page).to have_content new_casting_submission_heading
expect(page).not_to have_field interview_recording_field
end
scenario "admin can upload interview recording video when editing casting call interview" do
cc = create(:casting_call)
cci = create(:casting_submission, casting_call: cc)
expect(CastingSubmission.last.interview_recording).not_to be_attached
visit edit_admin_casting_submission_path(cci)
expect(page).to have_content edit_casting_submission_heading
expect(page).to have_field interview_recording_field
expect(page).not_to have_content current_interview_recording_label
attach_file interview_recording_field, Rails.root.join(file_fixture('video_file.mp4'))
click_on update_casting_submission_button
expect(page).to have_content casting_submission_updated_message
expect(CastingSubmission.last.interview_recording).to be_attached
end
scenario "when editing casting call interview with already uploaded interview video, interview recording file name link is shown below file field" do
cc = create(:casting_call)
cci = create(:casting_submission, :with_interview_recording, casting_call: cc)
expect(CastingSubmission.last.interview_recording).to be_attached
visit edit_admin_casting_submission_path(cci)
expect(page).to have_content edit_casting_submission_heading
expect(page).to have_content current_interview_recording_label
expect(page).to have_link CastingSubmission.last.interview_recording.attachment.blob.filename.to_s
end
scenario "when admin opens view page for casting submission, it does not fail if zoom meeting URL is invalid" do
cc = create(:casting_call)
cci = create(:casting_submission, casting_call: cc, zoom_meeting_url: "anything")
visit admin_casting_submissions_path
click_on manage_button
click_link view_link
expect(page).to have_content casting_submission_details_header
expect(page).to have_content interview_files_label
expect(page).to have_content cci.performer_name
end
scenario "admin can see copy url" do
cc = create(:casting_call)
cci = create(:casting_submission, casting_call: cc, zoom_meeting_url: "anything")
visit admin_casting_submissions_path
click_on manage_button
expect(page).to have_content "Copy URL"
end
private
def create_casting_submission_button
t 'admin.casting_submissions.index.actions.new'
end
def new_casting_submission_heading
t 'admin.casting_submissions.new.heading'
end
def edit_casting_submission_heading
'Edit Casting Submission'
end
def update_casting_submission_button
'Update Casting submission'
end
def submit_casting_submission_form
t 'helpers.submit.casting_submission.create'
end
def zoom_meeting_url_invalid_error
t 'casting_submissions.validation_errors.invalid_meeting_url'
end
def performer_name_field
'casting_submission[performer_name]'
end
def zoom_meeting_url_field
'casting_submission[zoom_meeting_url]'
end
def casting_call_field
'casting_submission[casting_call_id]'
end
def casting_submission_updated_message
t 'admin.casting_submissions.update.notice'
end
def interview_recording_field
'casting_submission[interview_recording]'
end
def current_interview_recording_label
'Current interview recording'
end
def manage_button
'Manage'
end
def view_link
'View'
end
def casting_submission_details_header
'Casting submission details'
end
def interview_files_label
'INTERVIEW FILES:'
end
end

View File

@@ -1,114 +0,0 @@
require "rails_helper"
feature "User managing casting calls" do
let(:current_user) { create(:user) }
let(:project) { create(:project, account: current_user.primary_account) }
before :each do
sign_in current_user
end
scenario "casting calls table is visible" do
visit project_casting_calls_path(project)
expect(page).to have_content "Created On"
expect(page).to have_content "Title"
expect(page).to have_content "Status"
end
scenario "sees list of casting calls" do
visit project_casting_calls_path(project)
expect(page).to have_content no_casting_calls_label
casting_call = create(:casting_call, project: project)
visit project_casting_calls_path(project)
expect(page).not_to have_content no_casting_calls_label
expect(page).to have_content casting_call.created_at.try(:strftime, '%D')
expect(page).to have_content casting_call.title
expect(page).to have_content casting_call.status
end
scenario "can create casting call requests" do
visit project_casting_calls_path(project)
expect(page).to have_content no_casting_calls_label
click_on add_new_casting_call_label
fill_in title_field, with: "Title"
fill_in description_field, with: "Description"
fill_in project_description_field, with: "Project Description"
fill_in interview_instructions_field, with: "Interview instructions"
fill_in interview_requirements_field, with: "Interview requirements"
fill_in questions_field, with: "Questions"
click_on "Create Casting call"
expect(page).to have_content("Your casting call request was successfully submitted. Thank you. A chat window will pop up on the lower right in a few seconds.")
end
scenario "can update casting call requests" do
create(:casting_call, title: "Title", project: project)
visit project_casting_calls_path(project)
click_on manage_button
click_on "Edit"
fill_in title_field, with: "New Title"
click_on "Update Casting call"
expect(page).to have_content("The casting call request has been updated")
end
scenario "can cancel a casting call request" do
create(:casting_call, title: "Title", project: project)
visit project_casting_calls_path(project)
click_on manage_button
click_on "Cancel"
expect(page).to have_content("The casting call request has been cancelled")
end
private
def no_casting_calls_label
"Casting calls will appear here"
end
def manage_button
t "casting_calls.casting_call.actions.manage"
end
def add_new_casting_call_label
t "casting_calls.index.actions.new"
end
def title_field
t "casting_calls.form.labels.title"
end
def description_field
t "casting_calls.form.labels.description"
end
def project_description_field
t "casting_calls.form.labels.project_description"
end
def interview_instructions_field
t "casting_calls.form.labels.interview_instructions"
end
def interview_requirements_field
t "casting_calls.form.labels.interview_requirements"
end
def questions_field
t "casting_calls.form.labels.questions"
end
end

View File

@@ -0,0 +1,188 @@
require "rails_helper"
feature "User managing casting calls" do
let(:current_user) { create(:user, :manager) }
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
before :each do
sign_in current_user
end
scenario "casting calls table is visible if there are existing casting calls" do
create(:casting_call, project: project)
visit project_casting_calls_path(project)
expect(page).to have_content "Created On"
expect(page).to have_content "Title"
expect(page).to have_content "Status"
end
scenario "splash page is shown if there are no existing records" do
visit project_casting_calls_path(project)
expect(page).to have_content schedule_demo
expect(page).to have_content create_casting_call
end
scenario "sees list of casting calls" do
casting_call = create(:casting_call, project: project)
visit project_casting_calls_path(project)
expect(page).not_to have_content no_casting_calls_label
expect(page).to have_content casting_call.created_at.try(:strftime, '%D')
expect(page).to have_content casting_call.title
expect(page).to have_content casting_call.status
end
scenario "can create casting call requests" do
visit project_casting_calls_path(project)
click_on add_new_casting_call_label
fill_in title_field, with: "Casting Title"
fill_in description_field, with: "Description"
fill_in project_description_field, with: "Project Description"
fill_in interview_instructions_field, with: "Welcome Message"
fill_in interview_requirements_field, with: "Goodbye Message"
fill_in questions_field, with: "Questions"
click_on "Create Casting call"
expect(page).to have_content("The casting call request has been created successfully.")
end
scenario "can update casting call requests" do
create(:casting_call, title: "Title", project: project)
visit project_casting_calls_path(project)
click_on manage_button
click_on "Edit"
fill_in title_field, with: "New Title"
click_on "Update Casting call"
expect(page).to have_content("The casting call request has been updated")
end
scenario "can cancel a casting call request" do
create(:casting_call, title: "Title", project: project)
visit project_casting_calls_path(project)
click_on manage_button
click_on "Cancel"
expect(page).to have_content("The casting call request has been cancelled")
end
scenario "can open casting call details" do
cc = create(:casting_call, title: "Dummy title", project: project)
visit project_casting_calls_path(project)
click_on manage_button
click_on view_button
expect(page).to have_content cc.title
expect(page).to have_content cc.description
expect(page).to have_content cc.project_description
expect(page).to have_content cc.created_at
expect(page).to have_content cc.status
expect(page).to have_content cc.interview_instructions
expect(page).to have_content cc.interview_requirements
expect(page).to have_content cc.questions
end
context 'When the user is associate' do
let(:current_user) { create(:user, :associate) }
it 'does show button to create new casting call' do
visit project_casting_calls_path(project)
expect(page).to have_content schedule_demo
expect(page).to have_content create_casting_call
end
end
context 'When the user is account manager' do
let(:current_user) { create(:user, :account_manager) }
it 'does show button to create new casting call' do
visit project_casting_calls_path(project)
expect(page).to have_content schedule_demo
expect(page).to have_content create_casting_call
end
end
context "when signed out" do
scenario "user opens public accessible casting call URL" do
cc = create(:casting_call, title: "Dummy title", project: project)
sign_out
public_url = "/casting_calls/#{cc.token}"
visit public_url
expect(page).to have_content cc.title
expect(page).to have_content cc.description
expect(page).to have_content cc.project_description
expect(page).not_to have_content cc.created_at
expect(page).not_to have_content cc.status
expect(page).not_to have_content cc.interview_instructions
expect(page).not_to have_content cc.interview_requirements
expect(page).not_to have_content cc.questions
end
end
private
def no_casting_calls_label
t 'casting_calls.index.empty'
end
def manage_button
t "casting_calls.casting_call.actions.manage"
end
def view_button
'View'
end
def add_new_casting_call_label
t "casting_calls.index.actions.new"
end
def title_field
t "helpers.label.casting_call.title"
end
def description_field
t "helpers.label.casting_call.description"
end
def project_description_field
t "helpers.label.casting_call.project_description"
end
def interview_instructions_field
t "helpers.label.casting_call.interview_instructions"
end
def interview_requirements_field
t "helpers.label.casting_call.interview_requirements"
end
def questions_field
t "helpers.label.casting_call.questions"
end
def create_casting_call
t 'casting_calls.splash.actions.create_casting_call'
end
def schedule_demo
t 'casting_calls.splash.actions.book_demo'
end
end

View File

@@ -1,52 +1,52 @@
require "rails_helper"
describe GenerateInterviewFilesZipJob do
describe GenerateCastingSubmissionFilesZipJob do
let(:project) { create(:project) }
let(:download) { create(:download, project: project, release_type: "CastingCallInterview", name: "my-title_john-doe") }
let(:download) { create(:download, project: project, release_type: "CastingSubmission", name: "my-title_john-doe") }
let(:casting_call) { create(:casting_call, project: project, title: "My Title") }
let(:casting_call_interview) { create(:casting_call_interview, casting_call: casting_call, performer_name: "John Doe") }
let(:casting_submission) { create(:casting_submission, casting_call: casting_call, performer_name: "John Doe") }
before do
dir = Rails.root.join("spec", "fixtures", "files")
files = ["contract.pdf", "AppearanceRelease.pdf"]
# Attachments in the test environment do not persist to cloud storage
# Therefore we want to stub calls to `open` with a cloud storage URL
allow_any_instance_of(InterviewFilesCollectionService).to receive(:open).and_return(StringIO.new("file data"))
allow_any_instance_of(InterviewFilesCollectionService).to receive(:build).and_yield(dir, files)
allow_any_instance_of(CastingSubmissionFilesCollectionService).to receive(:open).and_return(StringIO.new("file data"))
allow_any_instance_of(CastingSubmissionFilesCollectionService).to receive(:build).and_yield(dir, files)
end
describe ".perform_later" do
it "enqueues a background job for generating zip file" do
expect {
GenerateInterviewFilesZipJob.perform_later(project, download, casting_call_interview)
GenerateCastingSubmissionFilesZipJob.perform_later(project, download, casting_submission)
}.to have_enqueued_job
end
end
describe ".perform_now" do
it "updates a download record and creates attachment for it" do
GenerateInterviewFilesZipJob.perform_now(project, download, casting_call_interview)
GenerateCastingSubmissionFilesZipJob.perform_now(project, download, casting_submission)
expect(download.project).to eq project
expect(download.release_type).to eq "CastingCallInterview"
expect(download.release_type).to eq "CastingSubmission"
expect(download.name).to eq "my-title_john-doe"
expect(download.status).to eq "success"
expect(download.file).to be_attached
end
context "When there are errors" do
let(:error) { StandardError.new("Casting Call Interview files not found.") }
let(:error) { StandardError.new("Casting Submission files not found.") }
before do
allow(ProjectsChannel).to receive(:broadcast_download_generation_update).with(download, I18n.t("interview_downloads.download.failure"))
allow_any_instance_of(InterviewFilesCollectionService).to receive(:build).and_raise(StandardError, "Casting Call Interview files not found.")
allow(ProjectsChannel).to receive(:broadcast_download_generation_update).with(download, I18n.t("casting_submission_downloads.download.failure"))
allow_any_instance_of(CastingSubmissionFilesCollectionService).to receive(:build).and_raise(StandardError, "Casting Submission files not found.")
end
it "updates status to 'failure' and sends user a notification" do
GenerateInterviewFilesZipJob.perform_now(project, download, casting_call_interview)
GenerateCastingSubmissionFilesZipJob.perform_now(project, download, casting_submission)
expect(download.status).to eq "failure"
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(download, I18n.t("interview_downloads.download.failure"))
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(download, I18n.t("casting_submission_downloads.download.failure"))
end
end
end

View File

@@ -137,7 +137,7 @@ RSpec.describe Account do
MatchingRequest,
ActionMailbox::InboundEmail, # This is Rails model, we are not using it and it is NOT added to the Account#storage_total calculation
CastingCall,
CastingCallInterview
CastingSubmission
]
Rails.application.eager_load!
ActiveRecord::Base.descendants.each do |model|

View File

@@ -1,6 +1,8 @@
require 'rails_helper'
RSpec.describe CastingCallInterview, type: :model do
RSpec.describe CastingSubmission, type: :model do
subject { build(:casting_submission) }
describe "associations" do
it { is_expected.to belong_to(:casting_call) }
it { is_expected.to have_secure_token(:token) }