diff --git a/app/controllers/admin/casting_call_interviews_controller.rb b/app/controllers/admin/casting_call_interviews_controller.rb new file mode 100644 index 0000000..9ad520a --- /dev/null +++ b/app/controllers/admin/casting_call_interviews_controller.rb @@ -0,0 +1,65 @@ +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] + before_action :set_accounts, only: %i[new create edit] + + def index + @casting_call_interviews = casting_call_interviews.order_by_recent.paginate(page: params[:page]) + 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 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 set_accounts + @accounts = accounts + end + + def casting_call_interview_params + params.require(:casting_call_interview).permit(:casting_call_id, + :performer_name, + :interview_date, + :zoom_meeting_url, + :interview_recording) + 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 \ No newline at end of file diff --git a/app/models/casting_submission.rb b/app/models/casting_submission.rb index 6ac4f8f..d9262a7 100644 --- a/app/models/casting_submission.rb +++ b/app/models/casting_submission.rb @@ -1,6 +1,7 @@ class CastingSubmission < ApplicationRecord belongs_to :casting_call has_many_attached :files + has_one_attached :interview_recording has_secure_token diff --git a/app/views/admin/casting_submissions/_form.html.erb b/app/views/admin/casting_submissions/_form.html.erb index b615bc6..a4fd63b 100644 --- a/app/views/admin/casting_submissions/_form.html.erb +++ b/app/views/admin/casting_submissions/_form.html.erb @@ -6,6 +6,21 @@ <%= form.text_field :interview_date, class: "datepicker-control" %> <%= form.text_field :zoom_meeting_url %> + <% unless casting_call_interview.new_record? %> + <%= form.file_field :interview_recording, accept: "video/*", 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_call_interview.interview_recording.attached? %> +

+ <%= link_to casting_call_interview.interview_recording do %> + <%= fa_icon "file-text-o" %> <%= casting_call_interview.interview_recording.filename %> + <% end %> + <%= fa_icon "long-arrow-left" %> Current interview recording +

+ <% end %> + + + <% end %> +
<%= link_to t("shared.cancel"), [:admin, :casting_submissions], class: "col-3 text-reset" %>
diff --git a/db/structure.sql b/db/structure.sql index fcd9e16..c0259b4 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -9,20 +9,6 @@ SET xmloption = content; SET client_min_messages = warning; SET row_security = off; --- --- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: - --- - -CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; - - --- --- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: - --- - -COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; - - -- -- Name: fuzzystrmatch; Type: EXTENSION; Schema: -; Owner: - -- diff --git a/spec/factories/casting_calls.rb b/spec/factories/casting_calls.rb index 0db776a..434d27e 100644 --- a/spec/factories/casting_calls.rb +++ b/spec/factories/casting_calls.rb @@ -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" diff --git a/spec/factories/casting_submissions.rb b/spec/factories/casting_submissions.rb index a5b729f..f83935d 100644 --- a/spec/factories/casting_submissions.rb +++ b/spec/factories/casting_submissions.rb @@ -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 diff --git a/spec/features/admin_managing_casting_call_interviews_spec.rb b/spec/features/admin_managing_casting_call_interviews_spec.rb new file mode 100644 index 0000000..571d946 --- /dev/null +++ b/spec/features/admin_managing_casting_call_interviews_spec.rb @@ -0,0 +1,138 @@ +require "rails_helper" + +feature "Admin managing casting call interviews" 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 "admin cannot create casting call interview with invalid zoom url", js: true do + visit admin_casting_call_interviews_path + cc = create(:casting_call, title: "SpecialCastingCall") + + click_link create_casting_call_interview_button + expect(page).to have_content new_casting_call_interview_heading + + fill_in performer_name_field, with: "TestName" + select cc.title, from: casting_call_field + fill_in zoom_meeting_url_field, with: "malformed url" + + expect do + click_on submit_casting_call_interview_form + end.to change(CastingCallInterview, :count).by(0) + expect(page).to have_content zoom_meeting_url_invalid_error + + fill_in zoom_meeting_url_field, with: "https://similar.google.com/j/24324324?pwd=334kni3j4" + + expect do + click_on submit_casting_call_interview_form + end.to change(CastingCallInterview, :count).by(0) + expect(page).to have_content zoom_meeting_url_invalid_error + + fill_in zoom_meeting_url_field, with: "https://s01.zoom.us/j/343434?pwd=dawidj34ijij" + + expect do + click_on submit_casting_call_interview_form + end.to change(CastingCallInterview, :count).by(1) + expect(page).to have_content create_casting_call_interview_button + end + + scenario "when creating new casting call interview - interview recording field is not visible" do + visit admin_casting_call_interviews_path + + click_on create_casting_call_interview_button + + expect(page).to have_content new_casting_call_interview_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_call_interview, casting_call: cc) + + expect(CastingCallInterview.last.interview_recording).not_to be_attached + + visit edit_admin_casting_call_interview_path(cci) + + expect(page).to have_content edit_casting_call_interview_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_call_interview_button + expect(page).to have_content casting_call_updated_message + expect(CastingCallInterview.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_call_interview, :with_interview_recording, casting_call: cc) + + expect(CastingCallInterview.last.interview_recording).to be_attached + + visit edit_admin_casting_call_interview_path(cci) + + expect(page).to have_content edit_casting_call_interview_heading + expect(page).to have_content current_interview_recording_label + expect(page).to have_link CastingCallInterview.last.interview_recording.attachment.blob.filename.to_s + end + + private + + def create_casting_call_interview_button + t 'admin.casting_call_interviews.index.actions.new' + end + + def new_casting_call_interview_heading + t 'admin.casting_call_interviews.new.heading' + end + + def submit_casting_call_interview_form + t 'helpers.submit.casting_call_interview.create' + end + + def zoom_meeting_url_invalid_error + t 'casting_call_interviews.validation_errors.invalid_meeting_url' + end + + def performer_name_field + 'casting_call_interview[performer_name]' + end + + def zoom_meeting_url_field + 'casting_call_interview[zoom_meeting_url]' + end + + def casting_call_field + 'casting_call_interview[casting_call_id]' + end + + def create_casting_call_interview_button + 'Create Casting Call Interview' + end + + def update_casting_call_interview_button + 'Update Casting call interview' + end + + def edit_casting_call_interview_heading + 'Edit Casting Call Interview' + end + + def new_casting_call_interview_heading + 'New Casting Call Interview' + end + + def interview_recording_field + 'casting_call_interview[interview_recording]' + end + + def current_interview_recording_label + 'Current interview recording' + end + + def casting_call_updated_message + 'The casting call interview has been updated' + end +end