Compare commits

..

5 Commits

Author SHA1 Message Date
bilal
ee873a2cbe restore original file name 2020-06-04 15:07:44 +02:00
bilal
f99d607a69 enable admin to view task request details 2020-06-04 15:00:07 +02:00
Senad Uka
88836e937e Task me sync 2020-06-03 07:24:01 +02:00
bilal
e3d4d22a34 Handle QrMatching response - mock 2020-06-02 22:23:19 +02:00
Senad Uka
3690268f83 Sync of the branch 2020-06-01 18:59:15 +02:00
170 changed files with 1305 additions and 2746 deletions

View File

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

View File

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

View File

@@ -16,7 +16,6 @@ $(document).on "turbolinks:load", ->
switch data.event switch data.event
when "video_status_update" then @showVideoStatusUpdate(data.content) when "video_status_update" then @showVideoStatusUpdate(data.content)
when "download_status_update" then @showDownloadStatusUpdate(data.content) when "download_status_update" then @showDownloadStatusUpdate(data.content)
when "conference_recording_ready" then @showDownloadStatusUpdate(data.content)
showVideoStatusUpdate: (content) -> showVideoStatusUpdate: (content) ->
$("[data-ujs-target='video-analysis-msg']").replaceWith content $("[data-ujs-target='video-analysis-msg']").replaceWith content

View File

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

View File

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

View File

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

View File

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

View File

@@ -28,21 +28,10 @@ class BroadcastsChannel < ApplicationCable::Channel
recordings_content = ApplicationController.render partial: "broadcasts/broadcast_recordings", locals: { recordings: recordings, broadcast: broadcast } recordings_content = ApplicationController.render partial: "broadcasts/broadcast_recordings", locals: { recordings: recordings, broadcast: broadcast }
recordings_nav_content = ApplicationController.render partial: "broadcasts/broadcast_recording_nav", collection: recordings, as: :broadcast_recording recordings_nav_content = ApplicationController.render partial: "broadcasts/broadcast_recording_nav", collection: recordings, as: :broadcast_recording
broadcast_to broadcast, broadcast_to broadcast,
event: :stream_recording_ready, event: :stream_recording_ready,
flash_content: flash_content, flash_content: flash_content,
recordings_content: recordings_content, recordings_content: recordings_content,
recordings_nav_content: recordings_nav_content recordings_nav_content: recordings_nav_content
end end
def self.broadcast_file_upload_updates(broadcast, files, pagination_content)
files_content = ApplicationController.render partial: "broadcasts/file", collection: files
broadcast_to broadcast, {
event: :file_upload_update,
broadcast_token: broadcast.token,
files_content: files_content,
pagination_content: pagination_content
}
end
end end

View File

@@ -1,5 +1,5 @@
class ProjectsChannel < ApplicationCable::Channel class ProjectsChannel < ApplicationCable::Channel
def subscribed def subscribed
# TODO: How can we get the current account in this context # TODO: How can we get the current account in this context
project = current_user.accessible_projects_for(current_user.primary_account).find(params[:id]) project = current_user.accessible_projects_for(current_user.primary_account).find(params[:id])
@@ -25,12 +25,4 @@ class ProjectsChannel < ApplicationCable::Channel
content = ApplicationController.render partial: "application/flash", locals: { flash: flash } content = ApplicationController.render partial: "application/flash", locals: { flash: flash }
broadcast_to download.project, event: :download_status_update, content: content broadcast_to download.project, event: :download_status_update, content: content
end end
def self.conference_recording_ready(project, recording)
link = ApplicationController.helpers.link_to('Download here.', recording.service_url, target: '_blank', class: 'alert-link')
notification = "A recording of your video conference is now available. #{link}"
flash = OpenStruct.new(notice: notification)
content = ApplicationController.render partial: 'application/flash', locals: { flash: flash }
broadcast_to project, event: :conference_recording_ready, content: content
end
end end

View File

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

View File

@@ -0,0 +1,32 @@
class Admin::TaskRequestsController < Admin::ApplicationController
before_action :set_task_request, only: [:edit, :update, :show]
def index
@task_requests = task_requests.order_by_recent.paginate(page: params[:page])
end
def edit
end
def update
if @task_request.update(task_request_params)
redirect_to [:admin, :task_requests], notice: t(".notice")
else
render :edit
end
end
private
def task_request_params
params.require(:task_request).permit(:status, :deliverable_url)
end
def task_requests
policy_scope TaskRequest
end
def set_task_request
@task_request = authorize policy_scope(TaskRequest).find(params[:id])
end
end

View File

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

View File

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

View File

@@ -78,7 +78,7 @@ class AppearanceReleasesController < ApplicationController
end end
def appearance_release_params def appearance_release_params
params.require(:appearance_release).permit(:contract, :guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_photo, :guardian_email, :minor, params.require(:appearance_release).permit(:contract, :guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_photo, :minor,
:person_address, :person_first_name, :person_last_name, :person_phone, :person_email, :person_photo, :person_address, :person_first_name, :person_last_name, :person_phone, :person_email, :person_photo,
:applicable_medium_id, :applicable_medium_text, :applicable_medium_id, :applicable_medium_text,
:territory_id, :territory_text, :territory_id, :territory_text,

View File

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

View File

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

View File

@@ -61,12 +61,7 @@ class ContractTemplatesController < ApplicationController
:applicable_medium_id, :applicable_medium_text, :applicable_medium_id, :applicable_medium_text,
:territory_id, :territory_text, :territory_id, :territory_text,
:term_id, :term_text, :term_id, :term_text,
:restriction_id, :restriction_text, :restriction_id, :restriction_text)
:question_1_text, :question_2_text,
:question_3_text, :question_4_text,
:question_5_text, :question_6_text,
:question_7_text, :question_8_text,
:question_9_text, :question_10_text)
end end
def download_attributes def download_attributes

View File

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

View File

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

View File

@@ -18,7 +18,6 @@ class PasswordResetsController < ApplicationController
end end
def edit def edit
redirect_to new_session_path, notice: t(".notice") if @user.nil?
end end
def update def update

View File

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

View File

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

View File

@@ -41,7 +41,7 @@ class Public::AppearanceReleasesController < Public::BaseController
def appearance_release_params def appearance_release_params
params.require(:appearance_release).permit(:person_address, :person_first_name, :person_last_name, :person_phone, :person_email, :person_photo, params.require(:appearance_release).permit(:person_address, :person_first_name, :person_last_name, :person_phone, :person_email, :person_photo,
:guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_email, :guardian_photo, :minor, :guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_photo, :minor,
:signature_base64, :person_date_of_birth, :signature_base64, :person_date_of_birth,
:locale, :contract_template,) :locale, :contract_template,)
end end

View File

@@ -6,17 +6,14 @@ class Public::BroadcastsController < Public::BaseController
@conference_url = broadcast_zoom_meeting_url(@broadcast.token) @conference_url = broadcast_zoom_meeting_url(@broadcast.token)
@multi_view_broadcasts = multi_view_broadcasts @multi_view_broadcasts = multi_view_broadcasts
@recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page]) @recordings = @broadcast.broadcast_recordings.order_by_recent.paginate(page: params[:page])
@files = @broadcast.files.order("created_at DESC").paginate(page: params[:files_page]) @files = @broadcast.files.order("created_at DESC").paginate(page: params[:page])
render 'broadcasts/show' render 'broadcasts/show'
end end
def update def update
@broadcast.update(broadcast_params) @broadcast.update(broadcast_params)
@files = @broadcast.files.order("created_at DESC").paginate(page: 1) @files = @broadcast.files.order("created_at DESC").paginate(page: 1)
pagination_content = ApplicationController.render html: helpers.will_paginate(@files,params: { active_tab: params[:active_tab], page: params[:page], active_files_tab: params[:active_files_tab] })
BroadcastsChannel.broadcast_file_upload_updates(@broadcast, @files, pagination_content)
end end
private private
@@ -29,10 +26,7 @@ class Public::BroadcastsController < Public::BaseController
Broadcast. Broadcast.
where(token: params[:multi_view_tokens]). where(token: params[:multi_view_tokens]).
order_by_recent. order_by_recent.
map do |b| map { |b| MultiViewBroadcast.new(b, params[:multi_view_tokens]) }
files_page = params[:files_page] if params[:active_files_tab] == b.token
MultiViewBroadcast.new(b, params[:multi_view_tokens], files_page)
end
end end
def set_broadcast def set_broadcast
@@ -41,29 +35,20 @@ class Public::BroadcastsController < Public::BaseController
class MultiViewBroadcast class MultiViewBroadcast
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
delegate_missing_to :@broadcast delegate_missing_to :@broadcast
def initialize(broadcast, multi_view_tokens, paginate_page) def initialize(broadcast, multi_view_tokens)
@broadcast = broadcast @broadcast = broadcast
@multi_view_tokens = multi_view_tokens @multi_view_tokens = multi_view_tokens
@paginate_page = paginate_page
end end
def url def url
broadcast_url(uid, multi_view_tokens: @multi_view_tokens, host: AppHost.new.domain_with_port, locale: I18n.locale) broadcast_url(uid, multi_view_tokens: @multi_view_tokens, host: AppHost.new.domain_with_port, locale: I18n.locale)
end end
def files
@broadcast.files.order("created_at DESC").paginate(page: @paginate_page)
end
def uid def uid
token token
end end
def self.model_name
Broadcast.model_name
end
end end
end end

View File

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

View File

@@ -45,7 +45,7 @@ class Public::MaterialReleasesController < Public::BaseController
:person_first_name, :person_last_name, :person_title, :person_company, :person_phone, :person_email, :person_first_name, :person_last_name, :person_title, :person_company, :person_phone, :person_email,
:person_address_street1, :person_address_street2, :person_address_city, :person_address_state, :person_address_zip, :person_address_country, :person_address_street1, :person_address_street2, :person_address_city, :person_address_state, :person_address_zip, :person_address_country,
:signature_base64, :signature_base64,
:locale, :contract_template, :description, photos: [] :locale, :contract_template, :description
) )
end end

View File

@@ -1,86 +0,0 @@
class Public::MedicalReleasesController < Public::BaseController
before_action :set_account, :set_project, :set_contract_template
def new
@medical_release = build_medical_release
end
def create
@medical_release = build_medical_release(medical_release_params_with_locale_and_contract_template)
if @medical_release.save(context: :native)
if @medical_release.contract_template.present?
AttachContractToReleasableJob.perform_later(@medical_release)
end
log_create_analytics
else
render :new
end
end
private
def set_project
@project = @account.projects.find(params[:project_id])
end
def set_account
@account = Account.find_by(slug: params[:account_id])
end
def set_contract_template
@contract_template = @project.contract_templates.find(params[:contract_template_id])
end
def medical_releases
policy_scope(@project.medical_releases)
end
def build_medical_release(params = {})
authorize medical_releases.build(params)
end
def medical_release_params
params
.require(:medical_release)
.permit(
person_params,
:signature_base64,
:locale,
:contract_template,
:question_1_answer, :question_2_answer,
:question_3_answer, :question_4_answer,
:question_5_answer, :question_6_answer,
:question_7_answer, :question_8_answer,
:question_9_answer, :question_10_answer,
photos: [],
)
end
def person_params
[
:person_first_name,
:person_last_name,
:person_phone,
:person_email,
:person_address_street1,
:person_address_street2,
:person_address_city,
:person_address_state,
:person_address_zip,
:person_address_country,
]
end
def medical_release_params_with_locale
medical_release_params.merge(locale: I18n.locale)
end
def medical_release_params_with_locale_and_contract_template
medical_release_params_with_locale.merge(contract_template: @contract_template)
end
def log_create_analytics
TrackAnalyticsJob.perform_later(nil, nil, :track_create_native_release, release_type: MedicalRelease.to_s, account: @account, user_agent: request.user_agent, user_ip: request.remote_ip)
end
end

View File

@@ -0,0 +1,74 @@
class TaskRequestsController < ApplicationController
layout "project"
before_action :set_project
before_action :build_task_request, only: [:new, :create]
before_action :set_task_request, only: [:show, :edit, :update, :cancel]
def index
if params[:completed_only]
@task_requests = task_requests.completed.order_by_recent.paginate(page: params[:page])
else
@task_requests = task_requests.order_by_recent.paginate(page: params[:page])
end
end
def new
end
def create
@task_request.attributes = task_request_params
if @task_request.save
log_create_analytics
redirect_to [@project, :task_requests], notice: t(".notice")
else
render :new
end
end
def show
end
def edit
end
def update
if @task_request.update(task_request_params)
redirect_to [@project, :task_requests], notice: t(".notice")
else
render :edit
end
end
def cancel
@task_request.cancelled!
redirect_to [@project, :task_requests], notice: t(".notice")
end
private
def task_request_params
params.require(:task_request).permit(:description, :deadline, :time_allowed, :additional_notes, files: [])
end
def set_project
@project = policy_scope(Project).find(params[:project_id])
end
def set_task_request
@task_request = authorize policy_scope(TaskRequest).find(params[:id])
end
def task_requests
authorize policy_scope(@project.task_requests)
end
def build_task_request
@task_request = authorize @project.task_requests.build
end
def log_create_analytics
TrackAnalyticsJob.perform_later(Current.user, Current.account, :track_create_task_request, user_agent: request.user_agent, user_ip: request.remote_ip)
end
end

View File

@@ -5,7 +5,7 @@ class ZoomNotificationsController < ApplicationController
skip_before_action :verify_authenticity_token skip_before_action :verify_authenticity_token
before_action :authorize_zoom before_action :authorize_zoom
before_action :set_zoom_meeting, only: [:create], if: :meeting_event? before_action :set_zoom_meeting, only: :create
def create def create
case notification_event case notification_event
@@ -13,17 +13,8 @@ class ZoomNotificationsController < ApplicationController
@zoom_meeting.started! @zoom_meeting.started!
when 'meeting.ended' when 'meeting.ended'
@zoom_meeting.ended! @zoom_meeting.ended!
when 'recording.completed'
recording = notification.dig(:payload, :object, :recording_files).first
AttachRecordingToZoomMeetingJob.perform_later(@zoom_meeting, recording, notification['download_token'])
when 'user.deleted'
zoom_user = ZoomUser.find_by(api_id: notification.dig(:payload, :object, :id))
if zoom_user.present?
zoom_user.api_id = nil
zoom_user.destroy
end
else else
Rails.logger.info notification_event Rails.logger.info notification_type
Rails.logger.info notification Rails.logger.info notification
end end
@@ -32,24 +23,16 @@ class ZoomNotificationsController < ApplicationController
private private
def notification
params.to_unsafe_h
end
def notification_event def notification_event
notification.dig(:event) params.dig(:event)
end end
def notification_meeting_id def notification_meeting_id
notification.dig(:payload, :object, :id) params.dig(:payload, :object, :id)
end end
def notification_host_id def notification_host_id
notification.dig(:payload, :object, :host_id) params.dig(:payload, :object, :host_id)
end
def meeting_event?
notification_event.split(".").first.to_s.in? %w(meeting recording)
end end
def set_zoom_meeting def set_zoom_meeting

View File

@@ -41,7 +41,7 @@ module ContactInfoHelper
end end
def email_abbr(email) def email_abbr(email)
content_tag(:abbr, "E: ", title: "Email") + mail_to(email) content_tag(:abbr, "E: ", title: "Email") + email
end end
def phone_abbr(phone) def phone_abbr(phone)

View File

@@ -3,12 +3,8 @@ module DropzoneHelper
case releasable.model_name.param_key case releasable.model_name.param_key
when "acquired_media_release" when "acquired_media_release"
"To Add Photos & Videos to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse photos and connect to Camera" "To Add Photos & Videos to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse photos and connect to Camera"
when "material_release"
t 'material_releases.form.photos.dropzone_label'
when "music_release" when "music_release"
"To Add Audio Files to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files" "To Add Audio Files to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files"
when "location_release"
t 'location_releases.form.photos.dropzone_label'
when "directory" when "directory"
"To Add Files to the Folder:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files" "To Add Files to the Folder:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files"
else else

View File

@@ -1,25 +0,0 @@
class AttachRecordingToZoomMeetingJob < ApplicationJob
queue_as :default
def perform(zoom_meeting, recording_hash, download_token)
download_url = "#{recording_hash['download_url']}?access_token=#{download_token}"
file = URI.open(download_url)
if zoom_meeting.recording.attach(io: file, filename: file_name(zoom_meeting, recording_hash), content_type: 'video/mp4')
# Temorarily disabling notifications
# if zoom_meeting.project.present?
# ProjectsChannel.conference_recording_ready(zoom_meeting.project, zoom_meeting.recording)
# end
gateway = ZoomGateway.new
gateway.delete_recording(zoom_meeting.api_meeting_id, recording_hash['id'])
end
end
private
def file_name(zoom_meeting, recording_hash)
start = recording_hash['recording_start'].to_datetime
prefix = zoom_meeting.project.present? ? "#{zoom_meeting.project.name}_" : ''
"#{prefix}video_conference_date#{start.strftime("%Y-%m-%d")}_Time_#{start.strftime("%T")}.mp4"
end
end

View File

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

View File

@@ -54,9 +54,7 @@ class Account < ApplicationRecord
Download.where(project: projects), Download.where(project: projects),
User.joins(:project_memberships).where(project_memberships: { project: projects }), User.joins(:project_memberships).where(project_memberships: { project: projects }),
Broadcast.where(project: projects), Broadcast.where(project: projects),
ZoomMeeting.where(project: projects), TaskRequest.where(project: projects),
MedicalRelease.where(project: projects),
MatchingRequest.where(project: projects),
self self
])).sum(:byte_size).to_f ])).sum(:byte_size).to_f
end end
@@ -81,6 +79,10 @@ class Account < ApplicationRecord
plan_uid.to_s == "me_suite" || plan_uid.to_s == "releaseme" plan_uid.to_s == "me_suite" || plan_uid.to_s == "releaseme"
end end
def assistme_enabled?
plan_uid.to_s == "me_suite" || plan_uid.to_s == "assistme"
end
def plan_name def plan_name
case plan_uid.to_s case plan_uid.to_s
when "deliverme" when "deliverme"
@@ -89,6 +91,8 @@ class Account < ApplicationRecord
"DirectME" "DirectME"
when "releaseme" when "releaseme"
"ReleaseME" "ReleaseME"
when "assistme"
"AssistME"
when "me_suite" when "me_suite"
"ME Suite" "ME Suite"
end end

View File

@@ -43,8 +43,7 @@ class AcquiredMediaRelease < ApplicationRecord
person_address_street1 person_address_street2 person_address_city person_address_state person_address_zip person_address_country person_address_street1 person_address_street2 person_address_city person_address_state person_address_zip person_address_country
] ]
# CATEGORIES = ["Artwork", "Film Footage", "Video Footage", "Still Photograph"].freeze CATEGORIES = ["Artwork", "Film Footage", "Video Footage", "Still Photograph"].freeze
CATEGORIES = ["Film Footage", "Video Footage", "Still Photograph"].freeze
def minor? def minor?
false false

View File

@@ -39,7 +39,6 @@ class AppearanceRelease < ApplicationRecord
# These validations apply to releases being signed by a minor # These validations apply to releases being signed by a minor
with_options if: :minor? do with_options if: :minor? do
validates :guardian_first_name, :guardian_last_name, presence: true validates :guardian_first_name, :guardian_last_name, presence: true
validates :guardian_email, email: true, allow_blank: true
end end
validates :person_photo, content_type: face_photo_acceptable_content_types validates :person_photo, content_type: face_photo_acceptable_content_types

View File

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

View File

@@ -7,6 +7,8 @@ class Broadcast < ApplicationRecord
has_secure_token has_secure_token
scope :order_by_recent, -> { order(created_at: :desc) }
validates :name, presence: true validates :name, presence: true
enum status: [:created, :active, :idle] enum status: [:created, :active, :idle]

View File

@@ -1,6 +1,8 @@
class BroadcastRecording < ApplicationRecord class BroadcastRecording < ApplicationRecord
belongs_to :broadcast belongs_to :broadcast
scope :order_by_recent, -> { order(created_at: :desc) }
delegate :name, to: :broadcast, prefix: :broadcast delegate :name, to: :broadcast, prefix: :broadcast
validates :asset_uid, uniqueness: true validates :asset_uid, uniqueness: true

View File

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

View File

@@ -6,6 +6,8 @@ module Releasable
included do included do
belongs_to :project, touch: true belongs_to :project, touch: true
belongs_to :contract_template, optional: true belongs_to :contract_template, optional: true
scope :order_by_recent, -> { order(created_at: :desc) }
end end
def release_number def release_number

View File

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

View File

@@ -5,7 +5,7 @@ class HeadshotCollection
def self.for_project(project) def self.for_project(project)
appearance_releases_with_photo = project.appearance_releases.with_person_photo appearance_releases_with_photo = project.appearance_releases.with_person_photo
new(project.headshot_collection_uid, appearance_releases_with_photo + project.talent_releases) new(project.id, appearance_releases_with_photo + project.talent_releases)
end end
def initialize(collection_uid, releasables) def initialize(collection_uid, releasables)
@@ -23,7 +23,7 @@ class HeadshotCollection
collection_uid: collection_uid.to_s, collection_uid: collection_uid.to_s,
bucket_name: aws_bucket_name, bucket_name: aws_bucket_name,
ids_to_images: map_ids_to_images, ids_to_images: map_ids_to_images,
}.reject { |k, v| v.blank? && k != :ids_to_images } }
end end
private private

View File

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

View File

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

View File

@@ -4,4 +4,6 @@ class Note < ApplicationRecord
belongs_to :notable, polymorphic: true belongs_to :notable, polymorphic: true
validates :content, presence: true validates :content, presence: true
scope :order_by_recent, -> { order(created_at: :desc) }
end end

View File

@@ -3,8 +3,8 @@ class Project < ApplicationRecord
include Filterable include Filterable
include Syncable include Syncable
SIGNABLE_RELEASE_TYPES = %w(talent appearance acquired_media location material medical) SIGNABLE_RELEASE_TYPES = %w(talent appearance acquired_media location material)
AVAILABLE_RELEASE_TYPES = %w(appearance location material acquired_media talent music medical) AVAILABLE_RELEASE_TYPES = %w(appearance location material acquired_media talent music)
belongs_to :account belongs_to :account
has_many :acquired_media_releases, dependent: :destroy has_many :acquired_media_releases, dependent: :destroy
@@ -13,7 +13,6 @@ class Project < ApplicationRecord
has_many :material_releases, dependent: :destroy has_many :material_releases, dependent: :destroy
has_many :music_releases, dependent: :destroy has_many :music_releases, dependent: :destroy
has_many :talent_releases, dependent: :destroy has_many :talent_releases, dependent: :destroy
has_many :medical_releases, dependent: :destroy
has_many :videos, dependent: :destroy has_many :videos, dependent: :destroy
has_many :imports, dependent: :destroy has_many :imports, dependent: :destroy
has_many :contract_templates, dependent: :destroy has_many :contract_templates, dependent: :destroy
@@ -23,6 +22,7 @@ class Project < ApplicationRecord
has_many :downloads, dependent: :destroy has_many :downloads, dependent: :destroy
has_many :broadcasts, dependent: :destroy has_many :broadcasts, dependent: :destroy
has_many :zoom_meetings, dependent: :destroy has_many :zoom_meetings, dependent: :destroy
has_many :task_requests, dependent: :destroy
accepts_nested_attributes_for :project_memberships accepts_nested_attributes_for :project_memberships
@@ -34,7 +34,6 @@ class Project < ApplicationRecord
material_release: false, material_release: false,
music_release: false, music_release: false,
talent_release: false, talent_release: false,
medical_release: false,
video_analysis: false, video_analysis: false,
} }
end end
@@ -67,7 +66,6 @@ class Project < ApplicationRecord
material_release: true, material_release: true,
music_release: true, music_release: true,
talent_release: true, talent_release: true,
medical_release: true,
video_analysis: true, video_analysis: true,
} }
when "nat_geo" when "nat_geo"
@@ -79,7 +77,6 @@ class Project < ApplicationRecord
material_release: true, material_release: true,
music_release: true, music_release: true,
talent_release: true, talent_release: true,
medical_release: true,
video_analysis: true, video_analysis: true,
} }
else else
@@ -121,7 +118,7 @@ class Project < ApplicationRecord
current_zoom_meeting = zoom_meetings.active.first current_zoom_meeting = zoom_meetings.active.first
unless current_zoom_meeting.present? unless current_zoom_meeting.present?
zoom_user = ZoomUser.for_new_meeting zoom_user = ZoomUser.free.first || ZoomUser.create
current_zoom_meeting = ZoomMeeting.create(zoom_user: zoom_user, project: self) current_zoom_meeting = ZoomMeeting.create(zoom_user: zoom_user, project: self)
end end

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
class TaskRequest < ApplicationRecord
belongs_to :project
has_many_attached :files
enum status: [:pending, :completed, :cancelled]
scope :order_by_recent, -> { order(created_at: :desc) }
end

View File

@@ -1,10 +1,9 @@
require 'zoom_gateway'
class ZoomMeeting < ApplicationRecord class ZoomMeeting < ApplicationRecord
belongs_to :project, optional: true belongs_to :project, optional: true
belongs_to :zoom_user belongs_to :zoom_user
has_one_attached :recording
validates :recording, content_type: ['video/mp4']
enum status: [:created, :started, :ended] enum status: [:created, :started, :ended]
after_create :create_api_meeting, if: -> { api_meeting_id.nil? } after_create :create_api_meeting, if: -> { api_meeting_id.nil? }

View File

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

View File

@@ -3,8 +3,10 @@ class ContractTemplatePolicy < ApplicationPolicy
def resolve def resolve
if user.account_manager? if user.account_manager?
scope.left_outer_joins(:project).where(projects: {account: user.account}) scope.left_outer_joins(:project).where(projects: {account: user.account})
else elsif user.manager?
scope.left_outer_joins(project: :project_memberships).where(project_memberships: { user_id: user.id }) scope.left_outer_joins(project: :project_memberships).where(project_memberships: { user_id: user.id })
else
scope.none
end end
end end
end end
@@ -12,9 +14,8 @@ class ContractTemplatePolicy < ApplicationPolicy
def create? def create?
user.manager? || user.account_manager? user.manager? || user.account_manager?
end end
def show? def show?
true create?
end end
def destroy? def destroy?

View File

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

View File

@@ -36,4 +36,8 @@ class ProjectPolicy < ApplicationPolicy
def show_downloads? def show_downloads?
show? show?
end end
def show_task_results?
show?
end
end end

View File

@@ -0,0 +1,25 @@
class TaskRequestPolicy < 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

@@ -151,6 +151,24 @@ class Analytics
) )
end end
end end
def track_create_task_request(user_agent:, user_ip:)
if analytics_enabled?
identify
track(
{
user_id: user.id,
event: "Task request created",
properties: {
account: account.try(:name),
account_id: account.try(:id),
user_agent: user_agent,
ip: user_ip,
},
}
)
end
end
private private

View File

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

View File

@@ -7,6 +7,9 @@
<li class="nav-item"> <li class="nav-item">
<%= link_to fa_icon("users fw", text: "Users"), [:admin, :users], class: class_string("nav-link", "active" => controller_name == "users") %> <%= link_to fa_icon("users fw", text: "Users"), [:admin, :users], class: class_string("nav-link", "active" => controller_name == "users") %>
</li> </li>
<li class="nav-item">
<%= 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"> <li class="nav-item">
<%= link_to fa_icon("bug fw", text: "Errors"), "https://sentry.io/bigmedia/", class: "nav-link", target: :_blank %> <%= link_to fa_icon("bug fw", text: "Errors"), "https://sentry.io/bigmedia/", class: "nav-link", target: :_blank %>
</li> </li>

View File

@@ -0,0 +1,13 @@
<%= errors_summary_for task_request %>
<%= bootstrap_form_with model: model, local: true do |form| %>
<%= form.select :status, options_for_select(TaskRequest.statuses.except(:cancelled).keys, task_request.status), { class: "form-control" } %>
<%= form.text_field :deliverable_url %>
<div class="row align-items-center text-center mt-4">
<%= link_to t("shared.cancel"), [:admin, :task_requests], class: "col-3 text-reset" %>
<div class="col-9">
<%= form.submit class: class_string("btn btn-block", ["btn-success", "btn-primary"] => task_request.new_record?), data: { disable_with: t("shared.disable_with") } %>
</div>
</div>
<% end %>

View File

@@ -0,0 +1,26 @@
<tr id="<%= dom_id(task_request) %>">
<td>
<%= task_request.id %>
</td>
<td>
<%= task_request.created_at.strftime("%D") %>
</td>
<td>
<%= task_request.deadline.try(:strftime, '%D') %>
</td>
<td>
<%= task_request.time_allowed %>
</td>
<td>
<%= task_request.status.titleize %>
</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("tasks", text: "View"), [:admin, task_request], class: "dropdown-item", target: '_blank' %>
<%= link_to fa_icon("pencil", text: "Edit"), [:edit, :admin, task_request], class: "dropdown-item" %>
</div>
</div>
</td>
</tr>

View File

@@ -0,0 +1,6 @@
<div class="card shadow-sm">
<%= card_header text: "Edit Task Request", close_action_path: [:admin, :task_requests] %>
<div class="card-body">
<%= render "form", model: [:admin, @task_request], task_request: @task_request %>
</div>
</div>

View File

@@ -0,0 +1,23 @@
<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>Task ID</th>
<th>Created On</th>
<th>Deadline</th>
<th>Time Allowed</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody id="users">
<% if @task_requests.any? %>
<%= render @task_requests %>
<% else %>
<tr>
<td colspan="6" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>

View File

@@ -0,0 +1,18 @@
<dl>
<%= description_list_pair_for @task_request, :description, append: ":" %>
<%= description_list_pair_for @task_request, :created_at, append: ":" %>
<%= description_list_pair_for @task_request, :deadline, append: ":" %>
<%= description_list_pair_for @task_request, :time_allowed, append: ":" %>
<%= description_list_pair_for @task_request, :additional_notes, append: ":" %>
<%= description_list_pair_for @task_request, :status, append: ":" %>
<dt>Files:</dt>
<dd>
<% if @task_request.files.present? %>
<% @task_request.files.each do |file| %>
<%= link_to file.filename, rails_blob_path(file, disposition: 'attachment'), class: "btn btn-link" %><br/>
<% end %>
<% else %>
No files attached
<% end %>
</dd>
</dl>

View File

@@ -2,7 +2,7 @@
<td data-behavior="select"><%= check_box_tag "appearance_release_ids[]", appearance_release.id, false %></td> <td data-behavior="select"><%= check_box_tag "appearance_release_ids[]", appearance_release.id, false %></td>
<td> <td>
<% if appearance_release.photo.attached? %> <% if appearance_release.photo.attached? %>
<%= image_tag medium_variant(appearance_release.photo) %> <%= image_tag medium_variant(appearance_release.photo), class: "img-fluid" %>
<% else %> <% else %>
<%= fa_icon("warning", text: t(".no_photos"), class: "text-danger") %> <%= fa_icon("warning", text: t(".no_photos"), class: "text-danger") %>
<% end %> <% end %>
@@ -11,11 +11,10 @@
<%= appearance_release.name %> <%= appearance_release.name %>
</td> </td>
<td> <td>
<%= contact_info( <%= number_to_phone appearance_release.person_phone %>
address: appearance_release.person_address, </td>
phone: appearance_release.person_phone, <td>
email: appearance_release.person_email <%= mail_to appearance_release.person_email %>
) %>
</td> </td>
<td> <td>
<%= notes_preview appearance_release.notes.order_by_recent %> <%= notes_preview appearance_release.notes.order_by_recent %>

View File

@@ -52,7 +52,7 @@
<% end %> <% end %>
<div class="d-inline-block"> <div class="d-inline-block">
<%= form.hidden_field :person_photo, value: form.object.person_photo.signed_id if appearance_release.person_photo.attached?%> <%= form.hidden_field :person_photo, value: form.object.person_photo.signed_id if appearance_release.person_photo.attached?%>
<%= form.file_field :person_photo, hide_label: true, data: { ujs_target: "person-photo-input" }, help: "PNG or JPG only", accept: appearance_release.class.face_photo_acceptable_content_types.join(",") %> <%= form.file_field :person_photo, wrapper_class: "required", hide_label: true, required: !appearance_release.person_photo.attached?, data: { ujs_target: "person-photo-input" }, help: "PNG or JPG only", accept: appearance_release.class.face_photo_acceptable_content_types.join(",") %>
</div> </div>
</div> </div>

View File

@@ -46,7 +46,8 @@
<th data-behavior="all-selectable"><%= check_box_tag "appearance_release_ids[]", false, false %></th> <th data-behavior="all-selectable"><%= check_box_tag "appearance_release_ids[]", false, false %></th>
<th></th> <th></th>
<th><%= AppearanceRelease.human_attribute_name(:person_name) %></th> <th><%= AppearanceRelease.human_attribute_name(:person_name) %></th>
<th><%= AppearanceRelease.human_attribute_name(:contact_info) %></th> <th><%= AppearanceRelease.human_attribute_name(:person_phone) %></th>
<th><%= AppearanceRelease.human_attribute_name(:person_email) %></th>
<th><%= t(".table_headers.notes") %></th> <th><%= t(".table_headers.notes") %></th>
<th><%= t(".table_headers.tags") %></th> <th><%= t(".table_headers.tags") %></th>
<th><%= t(".table_headers.signed_at") %></th> <th><%= t(".table_headers.signed_at") %></th>

View File

@@ -35,6 +35,12 @@
<%= product_wordmark :deliver_me, class: class_string("d-inline-block", "disabled" => !Current.account.deliverme_enabled?) %> <%= product_wordmark :deliver_me, class: class_string("d-inline-block", "disabled" => !Current.account.deliverme_enabled?) %>
<% end %> <% end %>
</li> </li>
<li class="nav-item">
<%= link_to [project, :task_requests], class: class_string("nav-link", "active" => controller_name == "task_requests") do %>
<%= lock_icon_for(Current.account, :assistme) %>
<%= product_wordmark :assist_me, class: class_string("d-inline-block", "disabled" => !Current.account.assistme_enabled?) %>
<% end %>
</li>
</ul> </ul>
</nav> </nav>
<hr class="divider-light mx-n4"> <hr class="divider-light mx-n4">

View File

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

View File

@@ -1,4 +1,4 @@
<li class="my-2" id="<%= dom_id(file) %>"> <li class="my-2">
<% if file.variable? %> <% 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" %> <%= link_to image_tag(file.variant(resize_and_pad: [300, 300, background: "#F7F8F9"]), class: "bg-light img-thumbnail img-fluid"), file, target: "_blank" %>
<% else %> <% else %>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,6 @@
<% if releasable.model_name == "LocationRelease" %> <% if releasable.model_name == "LocationRelease" %>
<%= description_list_pair "Filming Started On:", releasable&.filming_started_on&.strftime("%D") %> <%= description_list_pair "Filming Started On:", releasable&.filming_started_on&.strftime("%D") %>
<%= description_list_pair "Filming Ended On:", releasable&.filming_ended_on&.strftime("%D") %> <%= description_list_pair "Filming Ended On:", releasable&.filming_ended_on&.strftime("%D") %>
<%= description_list_pair "Filming Hours:", releasable&.filming_hours %>
<% end %> <% end %>
<% if contract_template.fee? %> <% if contract_template.fee? %>
<%= description_list_pair "Fee:", number_to_currency(contract_template.fee) %> <%= description_list_pair "Fee:", number_to_currency(contract_template.fee) %>
@@ -39,15 +38,6 @@
<% end %> <% end %>
</dl> </dl>
<% if releasable.model_name == "MedicalRelease" %>
<% (1..10).each do |n| %>
<% if contract_template.public_send("question_#{n}_text").present? %>
<p><strong><%= contract_template.public_send("question_#{n}_text") %></strong></p>
<p><%= releasable.public_send("question_#{n}_answer") %></p>
<% end %>
<% end %>
<% end %>
<% if releasable.minor? %> <% if releasable.minor? %>
<br/> <br/>
<p class="text-left"><strong>Guardian Information</strong></p> <p class="text-left"><strong>Guardian Information</strong></p>
@@ -65,7 +55,6 @@
<%= description_list_pair_for releasable, :guardian_name, append: ":" %> <%= description_list_pair_for releasable, :guardian_name, append: ":" %>
<%= description_list_pair_for releasable, :guardian_address, append: ":" %> <%= description_list_pair_for releasable, :guardian_address, append: ":" %>
<%= description_list_pair_for releasable, :guardian_phone, append: ":" %> <%= description_list_pair_for releasable, :guardian_phone, append: ":" %>
<%= description_list_pair_for releasable, :guardian_email, append: ":" %>
<%= description_list_pair_for releasable, :signed_on, append: ":" %> <%= description_list_pair_for releasable, :signed_on, append: ":" %>
</dl> </dl>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,6 +16,11 @@
<%= link_to t("projects.show.downloads"), [@project, :downloads], class: "text-decoration-none text-reset stretched-link" %> <%= link_to t("projects.show.downloads"), [@project, :downloads], class: "text-decoration-none text-reset stretched-link" %>
<% end %> <% end %>
<% end %> <% end %>
<% if policy(Project).show_task_results? %>
<%= render "folder_card" do %>
<%= link_to t("projects.show.task_requests"), [@project, :task_requests, completed_only: true], class: "text-decoration-none text-reset stretched-link" %>
<% end %>
<% end %>
</div> </div>
<hr/> <hr/>

View File

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

View File

@@ -76,9 +76,6 @@
<%= form.text_field :guardian_last_name, required: @appearance_release.minor?, wrapper_class: "col-sm-3" %> <%= form.text_field :guardian_last_name, required: @appearance_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %>
</div> </div>
<div class="form-row">
<%= form.text_field :guardian_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row"> <div class="form-row">
<%= form.text_field :guardian_address, wrapper_class: "col-sm-6" %> <%= form.text_field :guardian_address, wrapper_class: "col-sm-6" %>
</div> </div>

View File

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

View File

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

View File

@@ -27,7 +27,11 @@
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %> <%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %> <%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %> <%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :person_company, wrapper_class: "col-sm-6" %> <%= form.text_field :person_company, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %> <%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
</div> </div>
@@ -41,14 +45,9 @@
<div class="form-row"> <div class="form-row">
<%= form.text_field :filming_started_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %> <%= form.text_field :filming_started_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %>
<%= form.text_field :filming_ended_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %> <%= form.text_field :filming_ended_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %>
<%= form.text_field :filming_hours, wrapper_class: "col-sm-12" %>
</div> </div>
<% end %> <% end %>
<%= card_field_set_tag t(".photos.heading") do %>
<%= render "shared/photos_dropzone_fields", form: form, release: @location_release %>
<% end %>
<%= card_field_set_tag t(".signature.heading") do %> <%= card_field_set_tag t(".signature.heading") do %>
<%= render "shared/signature_fields", form: form, instruction: 'An Authorized Signatory' %> <%= render "shared/signature_fields", form: form, instruction: 'An Authorized Signatory' %>
<% end %> <% end %>

View File

@@ -27,17 +27,17 @@
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %> <%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %> <%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %> <%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %> <%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :person_company, wrapper_class: "col-sm-6" %> <%= form.text_field :person_company, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %> <%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
</div> </div>
<%= render "shared/address_fields", form: form, subject: "person" %> <%= render "shared/address_fields", form: form, subject: "person" %>
<% end %> <% end %>
<%= card_field_set_tag t(".photo.heading") do %>
<%= render "shared/photos_dropzone_fields", form: form, release: @material_release %>
<% end %>
<hr> <hr>
<%= card_field_set_tag t(".signature.heading") do %> <%= card_field_set_tag t(".signature.heading") do %>

View File

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

View File

@@ -1,56 +0,0 @@
<div class="card shadow-sm">
<div class="card-body">
<%= errors_summary_for @medical_release %>
<%= bootstrap_form_with model: [@account, @project, @contract_template, @medical_release], local: true, validation_context: :native do |form| %>
<div class="alert alert-warning font-weight-bold"><%= t ".instructions_html", name: @project.name %></div>
<%= card_field_set_tag t(".legal.heading") do %>
<p><%= @contract_template.body %></p>
<% if @contract_template.fee? %>
<p>
Fee <span class="font-weight-bold text-success"><%= number_to_currency @contract_template.fee %></span>
</p>
<% end %>
<% end %>
<hr>
<% if (1..10).map {|n| @contract_template.public_send("question_#{n}_text").presence }.compact.any? %>
<%= card_field_set_tag t(".questionnaire.heading") do %>
<% (1..10).each do |n| %>
<% if @contract_template.public_send("question_#{n}_text").present? %>
<div class="form-row">
<%= form.text_area "question_#{n}_answer", wrapper_class: "col-sm-12", label: @contract_template.public_send("question_#{n}_text") %>
</div>
<% end %>
<% end %>
<% end %>
<hr>
<% end %>
<%= card_field_set_tag t(".personal_info.heading") do %>
<div class="alert alert-warning font-weight-bold"><%= t ".personal_info.instructions" %></div>
<div class="form-row">
<%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>
<% end %>
<hr>
<%= card_field_set_tag t(".photo.heading") do %>
<%= render "shared/photos_dropzone_fields", form: form, release: @medical_release %>
<% end %>
<%= card_field_set_tag t(".signature.heading") do %>
<%= render "shared/signature_fields", form: form %>
<% end %>
<div class="mt-5">
<%= form.button t("shared.submit_release_short"), class: "btn btn-block btn-lg btn-success", data: { disable_with: t("shared.disable_with") } %>
</div>
<% end %>
</div>
</div>

View File

@@ -11,6 +11,6 @@
</div> </div>
<%= form.form_group "#{field_name_prefix}address_country" do %> <%= form.form_group "#{field_name_prefix}address_country" do %>
<%= form.label "#{field_name_prefix}address_country" %> <%= form.label "#{field_name_prefix}address_country" %>
<%= form.country_select "#{field_name_prefix}address_country", { selected: 'US', priority: %w(US CA), prompt: true }, class: "form-control custom-select" %> <%= form.country_select "#{field_name_prefix}address_country", { priority: %w(US CA), prompt: true }, class: "form-control custom-select" %>
<% end %> <% end %>

View File

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

View File

@@ -0,0 +1,34 @@
<%= errors_summary_for task_request %>
<%= bootstrap_form_with model: model, local: true do |form| %>
<%= form.text_area :description %>
<%= form.text_field :deadline, class: "datepicker-control" %>
<%= form.text_field :time_allowed %>
<%= form.text_area :additional_notes %>
<%= field_set_tag content_tag(:span, "Files", class: "h6 text-muted text-uppercase") do %>
<div class="field d-none">
<%= form.label :files %>
<%= form.file_field :files, disable: true, direct_upload: true, multiple: true, id: "task_request_files", hide_label: true %>
<% task_request.files.each do |file| %>
<% unless file.persisted? %>
<%= hidden_field_tag "#{task_request.model_name.param_key}[files][]", file.signed_id %>
<% end %>
<% end %>
</div>
<div class="dropzone field border-dashed"
data-accepted-files="audio/*,image/*,video/*,application/*"
data-behavior="dropzone"
data-file-input-id="task_request_files"
data-existing-files="<%= mock_photos_json(task_request.files) %>"
data-placeholder="<%= dropzone_placeholder_message_for(task_request) %>"
data-submit-button="#submit_folder"></div>
<% end %>
<div class="row align-items-center text-center mt-4">
<%= link_to t("shared.cancel"), [project, :task_requests], class: "col-3 text-reset" %>
<div class="col-9">
<%= form.submit class: class_string("btn btn-block", ["btn-success", "btn-primary"] => task_request.new_record?), data: { disable_with: t("shared.disable_with") } %>
</div>
</div>
<% end %>

View File

@@ -0,0 +1,35 @@
<tr>
<td>
<%= task_request.created_at.strftime('%D') %>
</td>
<td>
<%= task_request.deadline.try(:strftime, '%D') %>
</td>
<td>
<%= task_request.time_allowed %>
</td>
<td>
<%= task_request.status.titleize %>
</td>
<% if params[:completed_only] %>
<td>
<%= task_request.deliverable_url %>
</td>
<% end %>
<td class="text-right">
<div class="btn-group">
<%= button_tag t(".actions.manage"), class: "btn btn-light btn-sm dropdown-toggle border", data: { toggle: "dropdown", boundary: "window" }, aria: { haspopup: true, expanded: false } %>
<div class="dropdown-menu dropdown-menu-right">
<% if policy(task_request).show? %>
<%= link_to fa_icon("tasks fw", text: "View"), [task_request.project, task_request], class: "dropdown-item", target: '_blank' %>
<% end %>
<% if policy(task_request).edit? %>
<%= link_to fa_icon("pencil fw", text: "Edit"), [:edit, task_request.project, task_request], class: "dropdown-item" %>
<% end %>
<% if policy(task_request).cancel? && !task_request.cancelled? %>
<%= link_to fa_icon("ban fw", text: "Cancel"), [:cancel, task_request.project, task_request], class: "dropdown-item", method: :post %>
<% end %>
</div>
</div>
</td>
</tr>

View File

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

View File

@@ -0,0 +1,41 @@
<%= product_wordmark :assist_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(TaskRequest).new? %>
<%= link_to fa_icon("plus", text: t(".actions.new")), [:new, @project, :task_request], 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.task_request_created_on") %></th>
<th><%= t(".table_headers.task_request_deadline") %></th>
<th><%= t(".table_headers.task_request_time_allowed") %></th>
<th><%= t(".table_headers.task_request_status") %></th>
<% if params[:completed_only] %>
<th><%= t(".table_headers.task_request_results") %></th>
<% end %>
<th></th>
</tr>
</thead>
<tbody id="task_requests">
<% if @task_requests.any? %>
<%= render @task_requests %>
<% else %>
<tr>
<td colspan="5" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="task_requests_pagination" class="mt-3">
<%= will_paginate @task_requests %>
</div>

View File

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

View File

@@ -0,0 +1,18 @@
<dl>
<%= description_list_pair_for @task_request, :description, append: ":" %>
<%= description_list_pair_for @task_request, :created_at, append: ":" %>
<%= description_list_pair_for @task_request, :deadline, append: ":" %>
<%= description_list_pair_for @task_request, :time_allowed, append: ":" %>
<%= description_list_pair_for @task_request, :additional_notes, append: ":" %>
<%= description_list_pair_for @task_request, :status, append: ":" %>
<dt>Files:</dt>
<dd>
<% if @task_request.files.present? %>
<% @task_request.files.each do |file| %>
<%= file.filename %><br>
<% end %>
<% else %>
"No files attached."
<% end %>
</dd>
</dl>

View File

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

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