Compare commits

..

11 Commits

Author SHA1 Message Date
bilal
dc9e364e6b fix MR comments 2020-06-18 10:06:31 +02:00
bilal
5454a0ecd2 fix MR comments 2020-06-18 09:58:46 +02:00
bilal
966137cd9d rebase master 2020-06-17 14:53:39 +02:00
bilal
fe4649ca64 use person_address_street1 for old person_address 2020-06-17 14:52:12 +02:00
bilal
e981ee28ee update specs 2020-06-17 14:51:28 +02:00
bilal
9c0d9b9919 make editing non-native release possible 2020-06-17 14:51:28 +02:00
bilal
dde1e975e2 make editing non-native release possible 2020-06-17 14:51:28 +02:00
bilal
3db2a39686 destructure address fields but use person_address_old for legacy 2020-06-17 14:51:28 +02:00
Senad Uka
a7b90c223b Upstream sync 2020-06-17 14:39:10 +02:00
Senad Uka
9a540efc74 Upstream sync 2020-06-16 17:11:04 +02:00
Senad Uka
028e946fcf Upstream sync 2020-06-15 08:33:23 +02:00
44 changed files with 777 additions and 176 deletions

View File

@@ -95,14 +95,28 @@ rake i18n:sort
```
## Zoom.us integration
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.
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.
#### Zoom.us api keys
1. Log in to you zoom.us account
2. Go to https://marketplace.zoom.us/develop/create
3. Choose JWT application
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

View File

@@ -8,11 +8,16 @@ $(document).on "turbolinks:load", ->
# Called when the subscription has been terminated by the server
received: (data) ->
return unless document.querySelector("meta[name=broadcast-token][content='#{broadcastToken}']")
switch data.event
when "broadcast_stream_update" then @refreshBroadcastVideo(data)
when "stream_recording_ready" then @showBroadcastRecordings(data)
when "file_upload_update" then @refreshBroadcastFilesTab(data)
when "broadcast_stream_update"
return unless document.querySelector("meta[name=broadcast-token][current=true][content='#{broadcastToken}']")
@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) ->
$("#broadcast_updates").html data.status_content

View File

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

View File

@@ -0,0 +1,50 @@
# 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,7 +3,6 @@
class AppearanceReleaseImportsController < ApplicationController
include AppearanceReleaseContext
include ProjectContext
include CreateReleasableJobs
before_action :set_project, only: [:create]
@@ -11,24 +10,16 @@ class AppearanceReleaseImportsController < ApplicationController
def create
authorize AppearanceRelease
@failed_files = []
attachments = appearance_release_params
if attachments.nil?
alert_message = t 'appearance_releases.create.no_attachments'
redirect_to [@project, :appearance_releases], alert: alert_message
else
attachments.each do |attachment|
create_imported_appearance_release attachment
end
MatchAppearanceReleasesJob.perform_later(@project, attachments)
notice_message = t 'appearance_releases.create.matching_started'
redirect_to [@project, :appearance_releases], notice: notice_message
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
private
@@ -45,45 +36,7 @@ class AppearanceReleaseImportsController < ApplicationController
params.require(:attachments)
end
def build_appearance_release(params = {})
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
def acceptable_extensions
AppearanceRelease.acceptable_import_file_extensions
end
end

View File

@@ -78,8 +78,8 @@ class AppearanceReleasesController < ApplicationController
end
def appearance_release_params
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,
params.require(:appearance_release).permit(:contract, :guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_photo, :guardian_email, :minor,
:person_address_street1, :person_first_name, :person_last_name, :person_phone, :person_email, :person_photo,
:applicable_medium_id, :applicable_medium_text,
:territory_id, :territory_text,
:term_id, :term_text, :person_date_of_birth,

View File

@@ -39,9 +39,25 @@ class Public::AppearanceReleasesController < Public::BaseController
authorize appearance_releases.build(params)
end
def person_params
%i[
person_first_name
person_last_name
person_phone
person_email
person_photo
person_address_street1
person_address_street2
person_address_city
person_address_state
person_address_zip
person_address_country
]
end
def appearance_release_params
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_photo, :minor,
params.require(:appearance_release).permit(person_params,
:guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_email, :guardian_photo, :minor,
:signature_base64, :person_date_of_birth,
:locale, :contract_template,)
end

View File

@@ -0,0 +1,100 @@
# 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

@@ -56,6 +56,7 @@ class Account < ApplicationRecord
Broadcast.where(project: projects),
ZoomMeeting.where(project: projects),
MedicalRelease.where(project: projects),
MatchingRequest.where(project: projects),
self
])).sum(:byte_size).to_f
end

View File

@@ -16,6 +16,17 @@ class AppearanceRelease < ApplicationRecord
has_one_attached :person_photo
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]
]
# These validations apply to all releases
validates :person_email, email: true, allow_blank: true
validates :person_first_name, :person_last_name, presence: true
@@ -39,6 +50,7 @@ class AppearanceRelease < ApplicationRecord
# These validations apply to releases being signed by a minor
with_options if: :minor? do
validates :guardian_first_name, :guardian_last_name, presence: true
validates :guardian_email, email: true, allow_blank: true
end
validates :person_photo, content_type: face_photo_acceptable_content_types
@@ -70,7 +82,18 @@ class AppearanceRelease < ApplicationRecord
scope :having_no_person_photo, -> { left_joins(:person_photo_attachment).group(:id).having('COUNT(active_storage_attachments) = 0') }
scope :with_person_name, ->(name) { where('person_first_name ILIKE ? OR person_last_name ILIKE ?', "%#{name}%") }
searchable_on %i[person_first_name person_last_name person_address person_email person_phone]
searchable_on %i[
person_first_name
person_last_name
person_address_street1
person_address_street2
person_address_city
person_address_state
person_address_zip
person_address_country
person_email
person_phone
]
# All releases must respond to the following messages
def name

View File

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

View File

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

View File

@@ -23,7 +23,7 @@ class HeadshotCollection
collection_uid: collection_uid.to_s,
bucket_name: aws_bucket_name,
ids_to_images: map_ids_to_images,
}.reject { |_, v| v.blank? }
}.reject { |k, v| v.blank? && k != :ids_to_images }
end
private

View File

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

View File

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

View File

@@ -8,7 +8,12 @@ class SampleAppearanceRelease < AppearanceRelease
def default_attrs
{
person_address: "Street Address, City, State Zipcode",
person_address_street1: "Street Address",
person_address_street2: "St2",
person_address_city: "City",
person_address_state: "State",
person_address_zip: "ZIP",
person_address_country: "Country",
person_first_name: "Some",
person_last_name: "Person",
person_phone: "555-555-5555",

View File

@@ -13,7 +13,7 @@
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
<%= form.date_field :person_date_of_birth, wrapper_class: "col-sm-6", placeholder: Date.current %>
<%= form.text_field :person_address, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_address_street1, wrapper_class: "col-sm-6" %>
</div>
<div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields">

View File

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

View File

@@ -3,12 +3,12 @@
<meta name="project-id" content="<%= @project.id %>">
<% end %>
<% if @broadcast %>
<meta name="broadcast-token" content="<%= @broadcast.token %>">
<meta name="broadcast-token" current="true" content="<%= @broadcast.token %>">
<% end %>
<% # Subscribe to Action Cable for every broadcast including those in multi-view %>
<% @multi_view_broadcasts.each do |multi_view_broadcast| %>
<% if multi_view_broadcast.token != @broadcast.token %>
<meta name="broadcast-token" content="<%= multi_view_broadcast.token %>">
<meta name="broadcast-token" current="false" content="<%= multi_view_broadcast.token %>">
<% end %>
<% end %>
<% end %>

View File

@@ -15,11 +15,6 @@
<%= render "shared/exploitable_rights_fields", form: form %>
<hr>
<% end %>
<%= field_set_tag content_tag(:span, t(".custom_fields.heading"), class: "h6 text-muted text-uppercase"), id: "custom_fields", style: "display: none;" do %>
<%= render "shared/custom_fields", form: form %>
<hr>
<% end %>
<%= field_set_tag content_tag(:span, t(".legal.heading"), class: "h6 text-muted text-uppercase") do %>
<%= form.form_group do %>
@@ -32,6 +27,12 @@
</div>
<% 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">
<%= link_to t("shared.cancel"), [project, :contract_templates], class: "col-3 text-reset" %>
<div class="col-3">

View File

@@ -65,6 +65,7 @@
<%= description_list_pair_for releasable, :guardian_name, append: ":" %>
<%= description_list_pair_for releasable, :guardian_address, 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: ":" %>
</dl>

View File

@@ -35,8 +35,8 @@
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
<%= form.date_field :person_date_of_birth, wrapper_class: "col-sm-6", placeholder: Date.current %>
<%= form.text_field :person_address, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>
<% end %>
<%= card_field_set_tag t(".photo.heading") do %>
@@ -76,6 +76,9 @@
<%= 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" %>
</div>
<div class="form-row">
<%= form.text_field :guardian_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :guardian_address, wrapper_class: "col-sm-6" %>
</div>

View File

@@ -112,6 +112,7 @@ en:
no_photos: Needs Photo
create:
failed_import: Failed to create appearance release for files listed below
matching_started: Matching started
no_attachments: Failed to import - no attachments
edit:
heading: Edit Appearance Release
@@ -141,6 +142,8 @@ en:
shared:
imported_appearance_release_contract_name: Imported Contract
imported_appearance_release_headshot_name: Imported Headshot
incomplete_match: Incomplete Match
matched_import: Complete Match
type_filter_actions:
all_releases: All Releases
complete_releases: Complete Releases
@@ -213,7 +216,8 @@ en:
archived_notice: The release template has been archived
form:
custom_fields:
heading: Custom Fields
heading: Medical Questionnaire
instructions: Please list the questions you wish the signer to answer. Any unused question fields will be hidden.
exploitable_rights:
heading: Exploitable Rights
legal:
@@ -325,8 +329,16 @@ en:
person_title: Title
appearance_release:
minor: Is the person a minor?
person_address: Address
person_address_city: City
person_address_country: Country
person_address_state: State
person_address_street1: Address
person_address_street2: Address (Line 2)
person_address_zip: Zip code
person_date_of_birth: Date of birth
person_email: Email address
person_first_name: First name
person_last_name: Last name
person_name: Name
person_phone: Phone number
location_release:
@@ -791,17 +803,17 @@ en:
instructions: >
Lastly, it's time for guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese!
instructions_html: >
Congrats in appearing on <em>%{name}</em>. Below is the appearance release form. After scrolling down and reading the appearance release form, please enter your personal information, take a selfie photo, and press the "Submit Release" button.
Congrats on appearing in <em>%{name}</em>. After scrolling down and reading the appearance release form, please enter your personal information, take a selfie photo and press the "Submit Release" button. If the person appearing on camera is a minor, you will enter their personal information first, select the button noting this person is a minor, and then enter your own personal info under "Guardian Information" at the bottom.
legal:
heading: Legal
personal_info:
heading: Personal Information
instructions: Now, enter your personal information.
instructions: Enter the personal information for the person appearing on camera.
photo:
camera_instructions_html: Click <em>Take Photo</em> to Turn ON Camera
heading: Take a Photo
heading: Photo of Person Appearing on Camera
instructions: >
Lastly, it's time for you to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese!
'Before you take your selfie photo, remove your hat and sunglasses (regular eyewear is okay). Make sure you are the only person in the frame, look straight at the camera and snap the photo. NOTE: If you are a Guardian, you must take the photo of the minor. Minor photo is required only for record keeping purposes to maintain proof of parental consent and to identify minor within the Program.'
no_photo: No photo yet
take_photo: Take Photo
warning: If your photo appears sideways, it will be autocorrected when you submit your release.

View File

@@ -25,6 +25,7 @@ es:
appearance_releases:
create:
failed_import: Failed to create appearance release for files listed below (ES)
matching_started: Matching started (ES)
no_attachments: Failed to import - no attachments (ES)
form:
photos:
@@ -37,6 +38,8 @@ es:
shared:
imported_appearance_release_contract_name: Contrato Importado
imported_appearance_release_headshot_name: Retrato Importado
incomplete_match: Incomplete Match (ES)
matched_import: Complete Match (ES)
type_filter_actions:
all_releases: All Releases (ES)
complete_releases: Complete Releases (ES)
@@ -52,6 +55,15 @@ es:
blank_contracts:
create:
number_of_copies_invalid_notice: Please enter valid number greater than 0 (ES)
form:
custom_fields:
heading: Medical Questionnaire (ES)
exploitable_rights:
heading: Exploitable Rights (ES)
legal:
heading: Legal (ES)
release_info:
heading: Release Info (ES)
contracts:
photos:
guardian_photo_heading: Guardian photo (ES)
@@ -106,8 +118,12 @@ es:
guardian_address: Dirección del tutor legal
guardian_name: Nómbre del tutor legal
guardian_phone: Número de teléfono del tutor legal
person_address_city: City (ES)
person_address_country: Country (ES)
person_address_state: State (ES)
person_address_street1: Address (ES)
person_address_street2: Address (Line 2) (ES)
minor: El firmante es un menor
person_address: Dirección
person_email: Dirección de correo electrónico
person_name: Nómbre
person_phone: Número de teléfono

View File

@@ -163,6 +163,7 @@ Rails.application.routes.draw do
resources :appearance_releases, only: [:show] do
resources :notes, controller: "notes", only: [:create, :index]
end
resources :direct_uploads, only: [:create]
end
end

View File

@@ -0,0 +1,9 @@
class CreateMatchingRequests < ActiveRecord::Migration[6.0]
def change
create_table :matching_requests do |t|
t.belongs_to :project, foreign_key: true
t.timestamps
end
end
end

View File

@@ -0,0 +1,5 @@
class AddIdentifierToAppearanceReleases < ActiveRecord::Migration[6.0]
def change
add_column :appearance_releases, :identifier, :string, default: nil
end
end

View File

@@ -0,0 +1,5 @@
class AddGuardianEmailToAppearanceReleases < ActiveRecord::Migration[6.0]
def change
add_column :appearance_releases, :guardian_email, :string
end
end

View File

@@ -0,0 +1,5 @@
class RemoveBroadcastIdFromZoomMeetings < ActiveRecord::Migration[6.0]
def change
remove_column :zoom_meetings, :broadcast_id
end
end

View File

@@ -0,0 +1,10 @@
class DestructurePersonAddressColumnInAppearanceReleases < ActiveRecord::Migration[6.0]
def change
rename_column :appearance_releases, :person_address, :person_address_street1
add_column :appearance_releases, :person_address_street2, :string
add_column :appearance_releases, :person_address_city, :string
add_column :appearance_releases, :person_address_state, :string
add_column :appearance_releases, :person_address_zip, :string
add_column :appearance_releases, :person_address_country, :string
end
end

View File

@@ -9,20 +9,6 @@ SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
--
CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
--
-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -
--
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
--
-- Name: fuzzystrmatch; Type: EXTENSION; Schema: -; Owner: -
--
@@ -304,7 +290,7 @@ ALTER SEQUENCE public.active_storage_blobs_id_seq OWNED BY public.active_storage
CREATE TABLE public.appearance_releases (
id bigint NOT NULL,
person_name_old character varying,
person_address character varying,
person_address_street1 character varying,
person_phone character varying,
project_id bigint,
created_at timestamp without time zone NOT NULL,
@@ -330,7 +316,14 @@ CREATE TABLE public.appearance_releases (
person_first_name character varying,
person_last_name character varying,
guardian_first_name character varying,
guardian_last_name character varying
guardian_last_name character varying,
identifier character varying,
guardian_email character varying,
person_address_street2 character varying,
person_address_city character varying,
person_address_state character varying,
person_address_zip character varying,
person_address_country character varying
);
@@ -885,6 +878,37 @@ CREATE SEQUENCE public.location_releases_id_seq
ALTER SEQUENCE public.location_releases_id_seq OWNED BY public.location_releases.id;
--
-- Name: matching_requests; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.matching_requests (
id bigint NOT NULL,
project_id bigint,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);
--
-- Name: matching_requests_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.matching_requests_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: matching_requests_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.matching_requests_id_seq OWNED BY public.matching_requests.id;
--
-- Name: material_releases; Type: TABLE; Schema: public; Owner: -
--
@@ -1632,7 +1656,6 @@ CREATE TABLE public.zoom_meetings (
api_meeting_id character varying,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
broadcast_id bigint,
zoom_user_id bigint,
project_id bigint,
status integer DEFAULT 0
@@ -1831,6 +1854,13 @@ ALTER TABLE ONLY public.imports ALTER COLUMN id SET DEFAULT nextval('public.impo
ALTER TABLE ONLY public.location_releases ALTER COLUMN id SET DEFAULT nextval('public.location_releases_id_seq'::regclass);
--
-- Name: matching_requests id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.matching_requests ALTER COLUMN id SET DEFAULT nextval('public.matching_requests_id_seq'::regclass);
--
-- Name: material_releases id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -2139,6 +2169,14 @@ ALTER TABLE ONLY public.location_releases
ADD CONSTRAINT location_releases_pkey PRIMARY KEY (id);
--
-- Name: matching_requests matching_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.matching_requests
ADD CONSTRAINT matching_requests_pkey PRIMARY KEY (id);
--
-- Name: material_releases material_releases_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2608,6 +2646,13 @@ CREATE INDEX index_location_releases_on_term_id ON public.location_releases USIN
CREATE INDEX index_location_releases_on_territory_id ON public.location_releases USING btree (territory_id);
--
-- Name: index_matching_requests_on_project_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_matching_requests_on_project_id ON public.matching_requests USING btree (project_id);
--
-- Name: index_material_releases_on_applicable_medium_id; Type: INDEX; Schema: public; Owner: -
--
@@ -2937,13 +2982,6 @@ CREATE INDEX index_videos_on_audio_analysis_uid ON public.videos USING btree (au
CREATE INDEX index_videos_on_project_id ON public.videos USING btree (project_id);
--
-- Name: index_zoom_meetings_on_broadcast_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_zoom_meetings_on_broadcast_id ON public.zoom_meetings USING btree (broadcast_id);
--
-- Name: index_zoom_meetings_on_project_id; Type: INDEX; Schema: public; Owner: -
--
@@ -3252,6 +3290,14 @@ ALTER TABLE ONLY public.material_releases
ADD CONSTRAINT fk_rails_6b945b36b9 FOREIGN KEY (contract_template_id) REFERENCES public.contract_templates(id);
--
-- Name: matching_requests fk_rails_71d16e64c8; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.matching_requests
ADD CONSTRAINT fk_rails_71d16e64c8 FOREIGN KEY (project_id) REFERENCES public.projects(id);
--
-- Name: appearance_releases fk_rails_7a58302526; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -3284,14 +3330,6 @@ ALTER TABLE ONLY public.music_releases
ADD CONSTRAINT fk_rails_890d967673 FOREIGN KEY (territory_id) REFERENCES public.territories(id);
--
-- Name: zoom_meetings fk_rails_8d814ea729; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.zoom_meetings
ADD CONSTRAINT fk_rails_8d814ea729 FOREIGN KEY (broadcast_id) REFERENCES public.broadcasts(id);
--
-- Name: medical_releases fk_rails_98aa92daa9; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -3611,12 +3649,17 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200424161117'),
('20200427073429'),
('20200428091105'),
('20200430151828'),
('20200430190412'),
('20200507110804'),
('20200512161738'),
('20200526113516'),
('20200603090419'),
('20200606044747'),
('20200610085411'),
('20200610140459');
('20200610140459'),
('20200612121539'),
('20200615131722'),
('20200615133602');

View File

@@ -10,5 +10,6 @@ require_relative "./brayniac_ai/edl_parse"
require_relative "./brayniac_ai/edl_parse_result"
require_relative "./brayniac_ai/facial_recognition"
require_relative "./brayniac_ai/facial_recognition_result"
require_relative "./brayniac_ai/qr_matching"
require_relative "./brayniac_ai/tag"
require_relative "./brayniac_ai/validation"

View File

@@ -0,0 +1,4 @@
module BrayniacAI
class QrMatching < Base
end
end

View File

@@ -0,0 +1,36 @@
require 'rails_helper'
RSpec.describe Api::DirectUploadsController, type: :controller do
let(:current_user) { create(:user) }
let(:project) { create(:project, account: current_user.primary_account) }
before do
sign_in_to_api(current_user)
end
describe '#create' do
it 'returns data for a direct upload' do
post :create, params: { direct_upload: direct_upload_params }
expect(response).to be_successful
expect(response_body_data_attributes).to include('id', 'key', 'signed_id', 'url', 'headers')
end
end
private
def direct_upload_params
file = file_fixture("video_file.mp4")
checksum = Digest::MD5.base64digest(StringIO.new(file.read).to_s)
{ filename: file.basename.to_s, content_type: "video/mp4", byte_size: file.size, checksum: checksum }
end
def response_body_data
JSON.parse(response.body).dig('data')
end
def response_body_data_attributes
response_body_data.dig('attributes')
end
end

View File

@@ -263,7 +263,9 @@ RSpec.describe AppearanceReleasesController, tye: :controller do
end
def minor_appearance_release_params
attributes_for(:appearance_release, :non_native, :minor_with_guardian_photo).except(:contract).merge(contract_param, exploitable_rights_params)
attributes_for(:appearance_release, :non_native, :minor_with_guardian_photo)
.except(:contract)
.merge(contract_param, exploitable_rights_params)
end
def exploitable_rights_params

View File

@@ -31,7 +31,7 @@ describe Public::AppearanceReleasesController do
contract_template = create(:contract_template, project: project)
sign_in(user)
post :create, params: { account_id: user.primary_account.to_param, project_id: project, contract_template_id: contract_template, appearance_release: { person_address: "Albuquerque" } }
post :create, params: { account_id: user.primary_account.to_param, project_id: project, contract_template_id: contract_template, appearance_release: { person_email: "email@email.com" } }
body = CGI.unescape_html(response.body)
expect(body).to match /Person first name can't be blank/
expect(body).to match /Person last name can't be blank/

View File

@@ -11,7 +11,12 @@ FactoryBot.define do
end
trait :native do
person_address "100 Test Lane, New York, NY 10001"
person_address_street1 "St1"
person_address_street2 "St2"
person_address_city "City"
person_address_state "State"
person_address_zip "ZIP"
person_address_country "Country"
person_phone "123-555-6789"
signature do
@@ -33,6 +38,7 @@ FactoryBot.define do
guardian_last_name "Doe"
guardian_address "100 Test Lane, New York, 10001"
guardian_phone "123-555-1234"
guardian_email "guardian@galaxy.all"
end
trait :minor_with_guardian_photo do
@@ -41,6 +47,7 @@ FactoryBot.define do
guardian_last_name "Doe"
guardian_address "100 Test Lane, New York, 10001"
guardian_phone "123-555-1234"
guardian_email "guardian@galaxy.all"
guardian_photo do
path = Rails.root.join("spec", "fixtures", "files", "pratt.jpg")
Rack::Test::UploadedFile.new(path, "image/jpeg")
@@ -65,5 +72,24 @@ FactoryBot.define do
appearance_release.contract_template = build(:appearance_release_contract_template)
end
end
factory :appearance_release_import do
person_photo nil
trait :with_headshot do
person_photo do
path = Rails.root.join("spec", "fixtures", "files", "person_photo.png")
Rack::Test::UploadedFile.new(path, "image/png")
end
end
trait :with_contract do
contract do
path = Rails.root.join("spec", "fixtures", "files", "AppearanceRelease.pdf")
Rack::Test::UploadedFile.new(path, "application/pdf")
end
end
end
end
end

View File

@@ -25,7 +25,7 @@ feature 'User managing appearance releases' do
fill_in person_date_of_birth, with: '01/01/1999'
attach_file person_photo_field, file_fixture('person_photo.png'), visible: :all
draw_signature file_fixture('signature.png'), 'appearance_release_signature_base64'
click_button 'I have read and agree to the above'
click_button submit_release_button
expect(page).to have_content(successful_submission_message)
end
@@ -45,6 +45,7 @@ feature 'User managing appearance releases' do
page.check person_is_minor_checkbox
expect(page).to have_content('GUARDIAN INFORMATION')
expect(page).to have_content('GUARDIAN PHOTO')
expect(page).to have_content 'Guardian Email'
fill_in guardian_first_name_field, with: 'Guardian'
fill_in guardian_last_name_field, with: 'Name'
@@ -58,7 +59,14 @@ feature 'User managing appearance releases' do
attach_file person_photo_field, file_fixture('person_photo.png'), visible: :all
attach_file guardian_photo_field, file_fixture('hemsworth.jpeg'), visible: :all
draw_signature file_fixture('signature.png'), 'appearance_release_signature_base64'
click_button 'I have read and agree to the above'
fill_in guardian_email_field, with: 'invalid@email'
click_button submit_release_button
expect(page).to have_content('Guardian email is not an email')
fill_in guardian_email_field, with: 'valid@email.com'
draw_signature file_fixture('signature.png'), 'appearance_release_signature_base64'
click_button submit_release_button
expect(page).to have_content(successful_submission_message)
end
@@ -130,48 +138,25 @@ feature 'User managing appearance releases' do
end
scenario 'progress bar shows when user imports a release', js: true do
skip "TODO"
visit project_appearance_releases_path(project)
expect(page).not_to have_css('#upload-progress-container')
large_pdf_file = build_large_pdf_file
attach_file import_appearance_release_field, Rails.root.join(large_pdf_file.path), visible: false
expect(page).to have_css('#upload-progress-container')
expect(page).to have_content submit_create_button, wait: 30
click_button submit_create_button
expect(page).to have_content matching_started
end
scenario 'MatchAppearanceReleasesJob is started when import is finished', js: true do
visit project_appearance_releases_path(project)
attach_file import_appearance_release_field, Rails.root.join(file_fixture('person_photo.png')), visible: false
expect(page).to have_content importing_label
allow(MatchAppearanceReleasesJob).to receive(:perform_later).with(project, anything)
click_button submit_create_button
expect(page).to have_css('.progress')
end
scenario 'importing a releases works when image is selected', js: true do
expect(page).to have_content matching_started
visit project_appearance_releases_path(project)
expect(page).to have_content submit_create_button
expect(page).to have_content no_appearance_releases
attach_file import_appearance_release_field, Rails.root.join(file_fixture('person_photo.png')), visible: false
expect(page).to have_content importing_label
click_button submit_create_button
expect(page).not_to have_content no_appearance_releases
expect(page).to have_content /Imported Headshot\s+\d{7}/
end
scenario 'importing a releases works when pdf is selected', js: true do
visit project_appearance_releases_path(project)
expect(page).to have_content submit_create_button
expect(page).to have_content no_appearance_releases
attach_file import_appearance_release_field, Rails.root.join(file_fixture('contract.pdf')), visible: false
expect(page).to have_content importing_label
click_button submit_create_button
expect(page).not_to have_content no_appearance_releases
expect(page).to have_content /Imported Contract\s+\d{7}/
end
scenario 'importing a releases fails when file other than image or pdf is selected', js: true do
visit project_appearance_releases_path(project)
expect(page).to have_content submit_create_button
expect(page).to have_content no_appearance_releases
attach_file import_appearance_release_field, Rails.root.join(file_fixture('audio.mp3')), visible: false
expect(page).to have_content importing_label
click_button submit_create_button
expect(page).to have_content failed_to_import_notice
expect(page).to have_content no_appearance_releases
end
@@ -249,6 +234,7 @@ feature 'User managing appearance releases' do
expect(pdf_body).to have_content('TAGS')
expect(pdf_body).to have_content('Woman')
expect(pdf_body).to have_content('Brunette')
expect(pdf_body).not_to have_content('Guardian Email')
end
scenario 'viewing contract PDF for a minor without guardian photo' do
@@ -262,8 +248,10 @@ feature 'User managing appearance releases' do
expect(pdf_filename).to include(appearance_release.filename_suffix.parameterize)
expect(pdf_body).to have_content(appearance_release.name)
expect(pdf_body).to have_content(appearance_release.guardian_name)
expect(pdf_body).to have_content(appearance_release.guardian_email)
expect(pdf_body).to have_content photos_heading.upcase
expect(pdf_body).to have_content(appearance_release.photo.filename.to_s)
expect(pdf_body).to have_content('Guardian Email')
end
scenario 'viewing contract PDF for a minor with guardian photo' do
@@ -277,9 +265,11 @@ feature 'User managing appearance releases' do
expect(pdf_filename).to include(appearance_release.filename_suffix.parameterize)
expect(pdf_body).to have_content(appearance_release.name)
expect(pdf_body).to have_content(appearance_release.guardian_name)
expect(pdf_body).to have_content(appearance_release.guardian_email)
expect(pdf_body).to have_content photos_heading(2).upcase
expect(pdf_body).to have_content(appearance_release.photo.filename.to_s)
expect(pdf_body).to have_content(appearance_release.guardian_photo.filename.to_s)
expect(pdf_body).to have_content('Guardian Email')
end
scenario 'deleting a release', js: true do
@@ -422,6 +412,10 @@ feature 'User managing appearance releases' do
tempfile
end
def matching_started
t 'appearance_releases.create.matching_started'
end
def filter_type_all
t 'appearance_releases.type_filter_actions.all_releases'
end
@@ -470,6 +464,10 @@ feature 'User managing appearance releases' do
'Guardian phone'
end
def guardian_email_field
'Guardian email'
end
def guardian_photo_field
'appearance_release[guardian_photo]'
end
@@ -479,15 +477,15 @@ feature 'User managing appearance releases' do
end
def person_first_name_field
'Person first name'
t('helpers.label.appearance_release.person_first_name')
end
def person_last_name_field
'Person last name'
t('helpers.label.appearance_release.person_last_name')
end
def person_address_field
t('helpers.label.appearance_release.person_address')
t('helpers.label.appearance_release.person_address_street1')
end
def person_email_field
@@ -518,6 +516,10 @@ feature 'User managing appearance releases' do
'Import Release'
end
def submit_release_button
'I have read and agree to the above'
end
def submit_update_button
'Save Changes'
end

View File

@@ -0,0 +1,216 @@
require "rails_helper"
describe MatchAppearanceReleasesJob do
let(:project) { create(:project) }
let(:dummy_appearance_release) { create(:appearance_release_import, :with_headshot, :with_contract) }
let(:dummy_matching_request) { instance_double(MatchingRequest, id: 999) }
before :all do
ENV["AWS_BUCKET"] = ""
end
describe ".perform_now" do
it "returns if no attachment is sent" do
expect(MatchingRequest).not_to receive(:create)
attachments = []
MatchAppearanceReleasesJob.perform_now project, attachments
end
it "returns if no valid attachment is sent" do
expect(MatchingRequest).not_to receive(:create)
dummy_video = create(:video)
attachments = [dummy_video.file.blob.signed_id]
MatchAppearanceReleasesJob.perform_now project, attachments
end
it "does not create new appearance release if BrayniacAI returns empty matches array" do
signed_ids = [dummy_appearance_release.person_photo.blob.signed_id]
keys = [dummy_appearance_release.person_photo.key]
payload = {
project: project,
attachments: signed_ids
}
qr_matching_payload = {
bucket: '',
files: keys,
request_id: dummy_matching_request.id
}
qr_matching_mock_response = double(
request_id: dummy_matching_request.id,
matches: []
)
expect(MatchingRequest).to receive(:create).with(payload).and_return(dummy_matching_request)
expect(BrayniacAI::QrMatching).to receive(:create!).with(qr_matching_payload).and_return(qr_matching_mock_response)
expect(dummy_matching_request).to receive(:destroy)
MatchAppearanceReleasesJob.perform_now project, signed_ids
expect(AppearanceRelease.last).to eq dummy_appearance_release
end
it "creates new incomplete appearance release if BrayniacAI returns single headshot match" do
signed_ids = [dummy_appearance_release.person_photo.blob.signed_id]
keys = [dummy_appearance_release.person_photo.key]
payload = {
project: project,
attachments: signed_ids
}
qr_matching_payload = {
bucket: '',
files: keys,
request_id: dummy_matching_request.id
}
mock_match = double(
headshots: keys,
contracts: [],
unknowns: [],
identifier: 'some/identifier/123'
)
matches = [mock_match]
qr_matching_mock_response = double(
request_id: dummy_matching_request.id,
matches: matches
)
expect(MatchingRequest).to receive(:create).with(payload).and_return(dummy_matching_request)
expect(BrayniacAI::QrMatching).to receive(:create!).with(qr_matching_payload).and_return(qr_matching_mock_response)
expect(dummy_matching_request).to receive(:destroy)
MatchAppearanceReleasesJob.perform_now project, signed_ids
expect(AppearanceRelease.last.identifier).to eq mock_match.identifier
expect(AppearanceRelease.last.person_photo).to be_attached
expect(AppearanceRelease.last.contract).not_to be_attached
end
it "creates new incomplete appearance release if BrayniacAI returns single contract match" do
signed_ids = [dummy_appearance_release.contract.blob.signed_id]
keys = [dummy_appearance_release.contract.key]
payload = {
project: project,
attachments: signed_ids
}
qr_matching_payload = {
bucket: '',
files: keys,
request_id: dummy_matching_request.id
}
mock_match = double(
headshots: [],
contracts: keys,
unknowns: [],
identifier: 'some/identifier/123'
)
matches = [mock_match]
qr_matching_mock_response = double(
request_id: dummy_matching_request.id,
matches: matches
)
expect(MatchingRequest).to receive(:create).with(payload).and_return(dummy_matching_request)
expect(BrayniacAI::QrMatching).to receive(:create!).with(qr_matching_payload).and_return(qr_matching_mock_response)
expect(dummy_matching_request).to receive(:destroy)
MatchAppearanceReleasesJob.perform_now project, signed_ids
expect(AppearanceRelease.last.identifier).to eq mock_match.identifier
expect(AppearanceRelease.last.person_photo.attached?).to eq false
expect(AppearanceRelease.last.contract.attached?).to eq true
end
it "creates new complete appearance release if BrayniacAI returns match for headshot and contract" do
signed_ids = [
dummy_appearance_release.person_photo.blob.signed_id,
dummy_appearance_release.contract.blob.signed_id
]
keys = [
dummy_appearance_release.person_photo.key,
dummy_appearance_release.contract.key
]
payload = {
project: project,
attachments: signed_ids
}
qr_matching_payload = {
bucket: '',
files: keys,
request_id: dummy_matching_request.id
}
mock_match = double(
headshots: [keys[0]],
contracts: [keys[1]],
unknowns: [],
identifier: 'some/identifier/123'
)
matches = [mock_match]
qr_matching_mock_response = double(
request_id: dummy_matching_request.id,
matches: matches
)
expect(MatchingRequest).to receive(:create).with(payload).and_return(dummy_matching_request)
expect(BrayniacAI::QrMatching).to receive(:create!).with(qr_matching_payload).and_return(qr_matching_mock_response)
expect(dummy_matching_request).to receive(:destroy)
MatchAppearanceReleasesJob.perform_now project, signed_ids
expect(AppearanceRelease.last.identifier).to eq mock_match.identifier
expect(AppearanceRelease.last.person_photo.attached?).to eq true
expect(AppearanceRelease.last.contract.attached?).to eq true
end
it "creates two new incomplete appearance releases if BrayniacAI returns two matches for headshot and contract" do
signed_ids = [
dummy_appearance_release.person_photo.blob.signed_id,
dummy_appearance_release.contract.blob.signed_id
]
keys = [
dummy_appearance_release.person_photo.key,
dummy_appearance_release.contract.key
]
payload = {
project: project,
attachments: signed_ids
}
qr_matching_payload = {
bucket: '',
files: keys,
request_id: dummy_matching_request.id
}
mock_match1 = double(
headshots: [keys[0]],
contracts: [],
unknowns: [],
identifier: 'some/identifier/123'
)
mock_match2 = double(
headshots: [],
contracts: [keys[1]],
unknowns: [],
identifier: 'some/identifier/789'
)
matches = [mock_match1, mock_match2]
qr_matching_mock_response = double(
request_id: dummy_matching_request.id,
matches: matches
)
expect(MatchingRequest).to receive(:create).with(payload).and_return(dummy_matching_request)
expect(BrayniacAI::QrMatching).to receive(:create!).with(qr_matching_payload).and_return(qr_matching_mock_response)
expect(dummy_matching_request).to receive(:destroy)
MatchAppearanceReleasesJob.perform_now project, signed_ids
releases = AppearanceRelease.last(2)
expect(releases[0].identifier).to eq mock_match1.identifier
expect(releases[0].person_photo.attached?).to eq true
expect(releases[0].contract.attached?).to eq false
expect(releases[1].identifier).to eq mock_match2.identifier
expect(releases[1].person_photo.attached?).to eq false
expect(releases[1].contract.attached?).to eq true
end
end
end

View File

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

View File

@@ -42,7 +42,6 @@ describe BlankContract do
material_release = create(:material_release_with_contract_template, project: project, person_name: 'Jane Doe')
result = render_contract_html_for(material_release)
expect(result).to include 'serial-number'
expect(result).to include 'DO NOT COPY'
end
end

View File

@@ -50,7 +50,11 @@ describe ContractTemplatePreview do
'id' => nil,
'person_first_name' => 'Dummy',
'person_last_name' => 'Person',
'person_address' => 'Street 1, Street 2, City, State 12345, Country',
'person_address_street1' => 'Street 1',
'person_address_street2' => 'Street 2',
'person_address_city' => 'City',
'person_address_state' => 'State',
'person_address_zip' => '12345',
'person_phone' => '00 111 222 333 4444',
'updated_at' => nil,
'minor' => true,

View File

@@ -29,7 +29,7 @@ module ExcelReports
restriction: Restriction.last,
person_first_name: "John",
person_last_name: "Doe",
person_address: "123 Main Street, New York, NY 10000")
person_address_street1: "123 Main Street, New York, NY 10000")
)
)
allow(sheet).to receive(:add_row)

View File

@@ -97,6 +97,18 @@ describe HeadshotCollection do
expect(hash.keys).not_to include(:collection_uid)
end
end
context "when there are no releasables" do
it "includes a blank hash value for the ids_to_images key" do
releases = []
collection = HeadshotCollection.new(nil, releases)
hash = collection.to_hash
expect(hash.keys).to include(:ids_to_images)
expect(hash[:ids_to_images]).to eq(Hash.new)
end
end
end
private