Master upstream sync

This commit is contained in:
Senad Uka
2020-07-16 18:02:45 +02:00
parent f04d34d337
commit add8304eab
50 changed files with 0 additions and 1626 deletions

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

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

@@ -1,76 +0,0 @@
class CastingCallsController < ApplicationController
layout "project"
before_action :set_project
before_action :build_casting_call, only: [:new, :create]
before_action :set_casting_call, only: [:show, :edit, :update, :cancel]
def index
@casting_calls = casting_calls.order_by_recent.paginate(page: params[:page])
end
def new
end
def create
@casting_call.attributes = casting_call_params_with_email
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"])
else
render :new
end
end
def show
render layout: 'application'
end
def edit
end
def update
if @casting_call.update(casting_call_params)
redirect_to [@project, :casting_calls], notice: t(".notice")
else
render :edit
end
end
def cancel
@casting_call.update(cancelled_at: Time.zone.now)
redirect_to [@project, :casting_calls], notice: t(".notice")
end
private
def casting_call_params
params.require(:casting_call).permit(:title, :description, :project_description, :interview_instructions, :interview_requirements, :questions)
end
def casting_call_params_with_email
casting_call_params.merge(user_email: Current.user.email)
end
def set_project
@project = policy_scope(Project).find(params[:project_id])
end
def set_casting_call
@casting_call = authorize casting_calls.find(params[:id])
end
def casting_calls
authorize policy_scope(@project.casting_calls)
end
def build_casting_call
@casting_call = authorize @project.casting_calls.build
end
def log_create_analytics
TrackAnalyticsJob.perform_later(Current.user, Current.account, :track_create_casting_call, user_agent: request.user_agent, user_ip: request.remote_ip)
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

@@ -1,14 +0,0 @@
class Public::CastingCallsController < Public::BaseController
skip_after_action :verify_authorized
before_action :set_casting_call, only: [:show]
def show
render layout: 'application'
end
private
def set_casting_call
@casting_call = CastingCall.find_by_token(params[:token])
end
end

View File

@@ -1,43 +0,0 @@
class GenerateInterviewFilesZipJob < ApplicationJob
queue_as :default
include Rails.application.routes.url_helpers
include ActionView::Helpers::UrlHelper
before_perform do |job|
@project = job.arguments.first
@download = job.arguments.second
@casting_call_interview = 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|
zipfile_name = "#{dir}/#{@download.name}.zip"
Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
files.each do |attachment|
zipfile.add(attachment, File.join("#{dir}/", attachment))
end
end
@download.file.attach(io: File.open(zipfile_name), filename: @download.name)
end
rescue StandardError => e
Raven.extra_context(
message: "Failed to generate download for project (##{project.id})",
release_type: "CastingCallInterview"
)
@download.failure!
ProjectsChannel.broadcast_download_generation_update(@download, I18n.t("interview_downloads.download.failure"))
end
after_perform do |job|
if @download.pending? && @download.file.attached?
@download.success!
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"))
end
end
end

View File

@@ -1,18 +0,0 @@
class CastingCall < ApplicationRecord
belongs_to :project
has_many :casting_call_interviews, dependent: :destroy
has_secure_token
def status
if cancelled?
"Cancelled"
else
"Active"
end
end
def cancelled?
self.cancelled_at.present?
end
end

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

@@ -1,29 +0,0 @@
class CastingCallInterviewPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
true
end
def destroy?
true
end
def update?
true
end
def complete?
true
end
def download?
true
end
end

View File

@@ -1,25 +0,0 @@
class CastingCallPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
true
end
def destroy?
true
end
def update?
true
end
def cancel?
true
end
end

View File

@@ -1,24 +0,0 @@
class InterviewFilesCollectionService
def initialize(files, folder_name)
@files = files
@folder_name = folder_name
end
def build
Dir.mktmpdir { |dir|
files.each do |file|
open("#{dir}/#{file.filename}", 'wb') do |tmp_file|
tmp_file << open(file.service_url.to_s).read
end
end
read_files = Dir.entries("#{dir}/").select { |f| !File.directory? f }
raise StandardError.new "Files not found." unless read_files.any?
yield(dir, read_files)
}
end
private
attr_reader :files, :folder_name
end

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,32 +0,0 @@
<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" %>
<% end %>
</div>
<div class="border bg-white rounded shadow-sm pb-3 table-responsive">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th>Account Name</th>
<th>Casting Call Request</th>
<th>Perfomer's Name</th>
<th>Interview Date</th>
<th></th>
</tr>
</thead>
<tbody id="users">
<% if @casting_call_interviews.any? %>
<%= render @casting_call_interviews %>
<% else %>
<tr>
<td colspan="20" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="casting_call_interviews_pagination" class="mt-3">
<%= will_paginate @casting_call_interviews %>
</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

@@ -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,26 +0,0 @@
<div class="border bg-white rounded shadow-sm pb-3 table-responsive">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th>Account Name</th>
<th>Casting Call Request</th>
<th>Perfomer's Name</th>
<th>Interviewed At</th>
<th></th>
</tr>
</thead>
<tbody id="users">
<% if @casting_call_interviews.any? %>
<%= render @casting_call_interviews %>
<% else %>
<tr>
<td colspan="20" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="casting_call_interviews_pagination" class="mt-3">
<%= will_paginate @casting_call_interviews %>
</div>

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

@@ -1,28 +0,0 @@
<tr>
<td>
<%= casting_call.created_at.strftime('%D') %>
</td>
<td>
<%= casting_call.title %>
</td>
<td>
<%= casting_call.status %>
</td>
<td class="text-right">
<div class="btn-group">
<%= button_tag t(".actions.manage"), class: "btn btn-light btn-sm dropdown-toggle border", data: { toggle: "dropdown", boundary: "window" }, aria: { haspopup: true, expanded: false } %>
<div class="dropdown-menu dropdown-menu-right">
<%= link_to fa_icon("link fw", text: "Copy Audition URL"), casting_call_url(casting_call.token), class: "dropdown-item", data: { behavior: "clipboard" } %>
<% if policy(casting_call).show? %>
<%= link_to fa_icon("tasks fw", text: "View"), [casting_call.project, casting_call], class: "dropdown-item", target: '_blank' %>
<% end %>
<% if policy(casting_call).edit? %>
<%= link_to fa_icon("pencil fw", text: "Edit"), [:edit, casting_call.project, casting_call], class: "dropdown-item" %>
<% end %>
<% if policy(casting_call).cancel? && !casting_call.cancelled? %>
<%= link_to fa_icon("ban fw", text: "Cancel"), [:cancel, casting_call.project, casting_call], class: "dropdown-item", method: :post %>
<% end %>
</div>
</div>
</td>
</tr>

View File

@@ -1,22 +0,0 @@
<%= errors_summary_for casting_call %>
<%= bootstrap_form_with model: model, url: [@project, @casting_call, show_chat: true], local: true do |form| %>
<div class="alert alert-info text-center text-md-left">
<%= fa_icon "info-circle" %>
<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') %>
<div class="row align-items-center text-center mt-4">
<%= link_to t("shared.cancel"), [project, :casting_calls], class: "col-3 text-reset" %>
<div class="col-9">
<%= 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 %>

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

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

View File

@@ -1,37 +0,0 @@
<%= product_wordmark :cast_me, class: "small mb-3" %>
<div class="row">
<div class="col-md-12">
<div class="d-md-flex d-sm-flex flex-sm-column flex-md-row flex-md-wrap mb-3">
<% if policy(CastingCall).new? %>
<%= link_to fa_icon("plus", text: t(".actions.new")), [:new, @project, :casting_call], class: "btn btn-primary mb-2" %>
<% end %>
</div>
</div>
</div>
<div class="border bg-white rounded shadow-sm pb-3 table-responsive">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th><%= t(".table_headers.casting_call_created_on") %></th>
<th><%= t(".table_headers.casting_call_title") %></th>
<th><%= t(".table_headers.casting_call_status") %></th>
<th></th>
</tr>
</thead>
<tbody id="casting_calls">
<% if @casting_calls.any? %>
<%= render @casting_calls %>
<% else %>
<tr>
<td colspan="20" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="casting_calls_pagination" class="mt-3">
<%= will_paginate @casting_calls %>
</div>

View File

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

View File

@@ -1,38 +0,0 @@
<% 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="card shadow-sm">
<%= card_header text: @casting_call.title, close_action_path: [@project, :casting_calls] %>
<div class="card-body">
<div class="row">
<div class="col-md-6 col-sm-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>
<% unless @casting_call.cancelled? %>
<div class="row align-items-center justify-content-center mt-3">
<%= link_to "Schedule an Audition", ENV["CASTME_AUDITION_BOOKING_URL"], target: "_blank", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>

View File

@@ -1,17 +0,0 @@
<p>Your <%= release_type.titleize %> files are being prepared for download. You will be notified when it's ready.
</p>
<p class="mt-3">The following downloads are also in progress:</p>
<ul>
<% downloads.each do |download| %>
<% 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"%>
<li><%= download.release_type.titleize %> files (as of <%= time_ago_in_words(download.created_at) %> ago)
</li>
<% else %>
<li><%= download.release_type.titleize %> contracts (as of <%= time_ago_in_words(download.created_at) %> ago)
</li>
<% end %>
<% end %>
</ul>

View File

@@ -1,51 +0,0 @@
<div class="card shadow-sm">
<%= card_header text: "Casting call interview 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: ":" %>
</dl>
</div>
</div>
<h6>INTERVIEW FILES:</h6>
<hr/>
<div class="row">
<div class="col-lg-12">
<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| %>
<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| %>
<% unless file.persisted? %>
<%= hidden_field_tag "#{@casting_call_interview.model_name.param_key}[files][]", file.signed_id %>
<% end %>
<% end %>
</div>
<div class="dropzone field border-dashed"
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-submit-button="#submit_folder"></div>
<div class="mt-5">
<%= form.button t(".update"), class: "btn btn-block btn-lg btn-success", data: { disable_with: t("shared.disable_with") } %>
</div>
<% end %>
</div>
</div>
</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" %>
</div>
</div>
</div>

View File

@@ -1,29 +0,0 @@
<% 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="card shadow-sm">
<%= card_header text: @casting_call.title %>
<div class="card-body">
<div class="row">
<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: ":" %>
</dl>
</div>
</div>
<% unless @casting_call.cancelled? %>
<div class="row align-items-center justify-content-center mt-3">
<%= link_to "Schedule an Audition", ENV["CASTME_AUDITION_BOOKING_URL"], target: "_blank", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>

View File

@@ -1,15 +0,0 @@
<% if params[:show_chat] %>
<%= javascript_include_tag "//js.hs-scripts.com/7344617.js", defer: "defer", async: true, id: "hs-script-loader" %>
<%= javascript_tag nonce: true do %>
function onConversationsAPIReady() {
window.HubSpotConversations.widget.load({ widgetOpen: true });
window.HubSpotConversations.widget.open();
}
if (window.HubSpotConversations) {
onConversationsAPIReady();
} else {
window.hsConversationsOnReady = [onConversationsAPIReady];
}
<% end %>
<% end %>

View File

@@ -1,17 +0,0 @@
class CreateCastingCalls < ActiveRecord::Migration[6.0]
def change
create_table :casting_calls do |t|
t.references :project
t.string :title
t.string :user_email
t.text :description
t.text :project_description
t.text :interview_instructions
t.text :interview_requirements
t.text :questions
t.datetime :cancelled_at
t.timestamps
end
end
end

View File

@@ -1,12 +0,0 @@
class CreateCastingCallInterviews < ActiveRecord::Migration[6.0]
def change
create_table :casting_call_interviews do |t|
t.references :casting_call, foreign_key: true
t.string :performer_name
t.string :zoom_meeting_url
t.datetime :interview_date
t.timestamps
end
end
end

View File

@@ -1,6 +0,0 @@
class AddTokenToCastingCalls < ActiveRecord::Migration[6.0]
def change
add_column :casting_calls, :token, :string
add_index :casting_calls, :token, unique: true
end
end

View File

@@ -1,6 +0,0 @@
class AddTokenToCastingCallInterviews < ActiveRecord::Migration[6.0]
def change
add_column :casting_call_interviews, :token, :string
add_index :casting_call_interviews, :token, unique: true
end
end

View File

@@ -1,5 +0,0 @@
class AddInterviewedAtToCastingCallInterview < ActiveRecord::Migration[6.0]
def change
add_column :casting_call_interviews, :interviewed_at, :datetime
end
end

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

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

@@ -1,126 +0,0 @@
require 'rails_helper'
RSpec.describe CastingCallsController, type: :controller do
render_views
let(:user) { create(:user) }
let(:account) { user.primary_account }
let(:project) { create(:project, account: user.primary_account) }
before do
sign_in user
end
describe "#index" do
it "responds successfully" do
get :index, params: { project_id: project }
expect(response).to be_successful
end
it "renders content" do
create(:casting_call, project: project)
get :index, params: { project_id: project }
expect(response.body).to have_link "Create Casting Call"
expect(response.body).to have_content "Active"
end
context "when there are many records" do
it "paginates the table" do
create_list(:casting_call, 20, project: project)
get :index, params: { project_id: project }
expect(response.body).to have_link("2", href: project_casting_calls_path(project, page: 2))
end
end
end
describe "#new" do
it "responds successfully" do
get :new, params: { project_id: project }
expect(response).to be_successful
expect(assigns(:casting_call)).to be_a_new(CastingCall)
expect(response).to render_template(:new)
end
end
describe "#create" do
it "does create a new record" do
expect {
post :create, params: { project_id: project.id, casting_call: casting_call_params }
}.to change(CastingCall, :count)
end
it "logs an event" do
expect {
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
let!(:casting_call) { create(:casting_call, project: project, description: "My description" ) }
it "updates casting call request" do
patch :update, params: { project_id: project.id, id: casting_call.id, casting_call: update_params }
expect(casting_call.reload.description).to eq("This is updated description")
end
end
describe "#show" do
let!(:casting_call) { create(:casting_call, project: project, description: "Casting Call Request") }
it "responds successfully" do
get :show, params: { project_id: project.id, id: casting_call.id }
expect(response).to be_successful
expect(assigns(:casting_call)).to eq(casting_call)
end
it "renders content" do
get :show, params: { project_id: project.id, id: casting_call.id }
expect(response.body).to have_content "Casting Call Request"
expect(response.body).to have_content "Active"
end
end
describe "#cancel" do
let!(:casting_call) { create(:casting_call, project: project, description: "Casting Call to be Cancelled") }
it "responds with redirect" do
post :cancel, params: { project_id: project.id, id: casting_call.id }
expect(response).to be_redirect
expect(response).to redirect_to(project_casting_calls_path(project))
expect(flash.notice).not_to be_nil
end
it "updates the status to 'Cancelled'" do
expect {
post :cancel, params: { project_id: project.id, id: casting_call.id }
}.to change { casting_call.reload.status }.from("Active").to("Cancelled")
end
end
private
def casting_call_params
attributes_for(:casting_call).except(:status, :user_email)
end
def update_params
{ description: "This is updated description" }
end
end

View File

@@ -1,58 +0,0 @@
require "rails_helper"
RSpec.describe InterviewDownloadsController, 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") }
before do
sign_in current_user
end
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)
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
}.to change(Download, :count).by(1)
expect(Download.last.status).to eq('not_started')
end
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"))
post :create, params: { project_id: project.id, casting_call_interview_id: casting_call_interview.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"))
end
end
context "When there are existing jobs" do
let(:appearance_release_download) { create(:download, project_id: project.id, name: "#{project.name.parameterize}_appearance-releases") }
let(:acquired_media_release_download) { create(:download, project_id: project.id, name: "#{project.name.parameterize}_acquired-media-releases", release_type: "AcquiredMediaRelease") }
before do
allow(Download).to receive_message_chain(:unfinished_desc_order, :offset).and_return([acquired_media_release_download, appearance_release_download])
allow(ProjectsChannel).to receive(:broadcast_download_generation_update)
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"
post :create, params: { project_id: project.id, casting_call_interview_id: casting_call_interview.id }, format: :js
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(be_kind_of(Download), broadcast_message)
end
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

@@ -1,28 +0,0 @@
require 'rails_helper'
RSpec.describe Public::CastingCallsController, type: :controller do
render_views
describe "#show" do
let(:casting_call) { create(:casting_call) }
it "responds successfully" do
get :show, params: { token: casting_call.token }
expect(response).to be_successful
expect(assigns(:casting_call)).to eq(casting_call)
end
it "shows casting call details" do
get :show, params: { token: casting_call.token }
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
end

View File

@@ -1,13 +0,0 @@
FactoryBot.define do
factory :casting_call_interview do
association :casting_call
performer_name 'John Doe'
zoom_meeting_url 'https://us04web.zoom.us/j/1111111111?pwd=aDZCS1dzZ2lWdDZJcHBhVnNIclB4QT03'
interview_date { 10.days.from_now }
interviewed_at { nil }
trait :with_files do
files { [Rack::Test::UploadedFile.new('spec/fixtures/files/location_photo.png', 'image/png')] }
end
end
end

View File

@@ -1,15 +0,0 @@
FactoryBot.define do
factory :casting_call do
association :project
user_email 'test@email.com'
description "Casting call description"
project_description "Casting call project description"
interview_instructions "Interview instructions"
interview_requirements "Interview requirements"
questions "Questions"
trait :cancelled do
cancelled_at { Time.zone.now }
end
end
end

View File

@@ -1,155 +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
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 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
"Casting calls will appear here"
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 "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

@@ -1,60 +0,0 @@
require "rails_helper"
describe GenerateInterviewFilesZipJob do
let(:project) { create(:project) }
let(:download) { create(:download, project: project, release_type: "CastingCallInterview", 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") }
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)
end
describe ".perform_later" do
it "enqueues a background job for generating zip file" do
expect {
GenerateInterviewFilesZipJob.perform_later(project, download, casting_call_interview)
}.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)
expect(download.project).to eq project
expect(download.release_type).to eq "CastingCallInterview"
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.") }
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.")
end
it "updates status to 'failure' and sends user a notification" do
GenerateInterviewFilesZipJob.perform_now(project, download, casting_call_interview)
expect(download.status).to eq "failure"
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(download, I18n.t("interview_downloads.download.failure"))
end
end
end
after do
# Delete the file created in fixture.
# Or the tests will fail on next run due to already existing files in existing zip.
path = Rails.root.join("spec", "fixtures", "files")
File.delete("#{path}/my-title_john-doe.zip") if File.exists? "#{path}/my-title_john-doe.zip"
end
end

View File

@@ -1,12 +0,0 @@
require 'rails_helper'
RSpec.describe CastingCallInterview, type: :model do
describe "associations" do
it { is_expected.to belong_to(:casting_call) }
it { is_expected.to have_secure_token(:token) }
end
describe "validations" do
it { is_expected.to validate_presence_of(:performer_name) }
end
end

View File

@@ -1,11 +0,0 @@
require 'rails_helper'
RSpec.describe CastingCall, type: :model do
describe "associations" do
it { is_expected.to belong_to(:project) }
end
describe "validations" do
it { is_expected.to have_secure_token(:token) }
end
end

View File

@@ -1,91 +0,0 @@
require "rails_helper"
describe CastingCallPolicy do
subject { described_class }
let(:user_context) { build(:user_context, user: user, account: user.primary_account) }
context "for an associate" do
let(:user) { create(:user, :associate, admin: false) }
permissions :index? do
it { is_expected.to permit(user_context, subject) }
end
permissions :create? do
it { is_expected.to permit(user_context, subject) }
end
permissions :show? do
it { is_expected.to permit(user_context, subject) }
end
permissions :destroy? do
it { is_expected.to permit(user_context, subject) }
end
permissions :update? do
it { is_expected.to permit(user_context, subject) }
end
permissions :cancel? do
it { is_expected.to permit(user_context, subject) }
end
end
context "for a project manager" do
let(:user) { create(:user, :manager, admin: false) }
permissions :index? do
it { is_expected.to permit(user_context, subject) }
end
permissions :create? do
it { is_expected.to permit(user_context, subject) }
end
permissions :show? do
it { is_expected.to permit(user_context, subject) }
end
permissions :destroy? do
it { is_expected.to permit(user_context, subject) }
end
permissions :update? do
it { is_expected.to permit(user_context, subject) }
end
permissions :cancel? do
it { is_expected.to permit(user_context, subject) }
end
end
context "for account managers" do
let(:user) { create(:user, :account_manager, admin: false) }
permissions :index? do
it { is_expected.to permit(user_context, subject) }
end
permissions :create? do
it { is_expected.to permit(user_context, subject) }
end
permissions :show? do
it { is_expected.to permit(user_context, subject) }
end
permissions :destroy? do
it { is_expected.to permit(user_context, subject) }
end
permissions :update? do
it { is_expected.to permit(user_context, subject) }
end
permissions :cancel? do
it { is_expected.to permit(user_context, subject) }
end
end
end