Compare commits

...

20 Commits

Author SHA1 Message Date
Bilal
d3a240464d manually report exception to sentry 2020-07-06 15:37:59 +02:00
Senad Uka
7cdb814d6d Upstream sync 2020-07-06 10:22:04 +02:00
Senad Uka
2dea0f29b9 Upstream sync 2020-07-03 10:23:03 +02:00
Senad Uka
d6a3542308 Upstream sync 2020-07-02 10:34:24 +02:00
Senad Uka
e49498bbbf Upstream sync 2020-07-01 06:39:02 +02:00
Senad Uka
dd0ac5b110 Upstream sync 2020-06-30 05:07:43 +02:00
Senad Uka
8951667e61 Upstrream sync 2020-06-26 18:45:11 +02:00
Senad Uka
fe131491cd Upstream sync 2020-06-26 04:55:50 +02:00
Senad Uka
290dbfa48b Upstream sync 2020-06-25 08:46:11 +02:00
Senad Uka
319cd89b29 Upstream sync 2020-06-24 04:48:12 +02:00
Senad Uka
6b0ea5b7df Upstream sync 2020-06-23 17:10:53 +02:00
Senad Uka
afee9d9bc9 Upstream sync 2020-06-22 20:28:22 +02:00
Senad Uka
072142811f Upstream sync 2020-06-22 14:14:25 +02:00
Senad Uka
b924b99762 Upstream sync 2020-06-19 09:23:07 +02:00
Senad Uka
988ef2beab Upstream sync 2020-06-18 17:51:08 +02:00
Senad Uka
1168bcdfdd Upstream sync 2020-06-18 16:56:11 +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
Senad Uka
fbf3173747 Upstream sync 2020-06-12 16:38:59 +02:00
214 changed files with 7144 additions and 642 deletions

View File

@@ -4,7 +4,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "2.6.3" ruby "2.6.3"
# Bundle edge Rails instead: gem "rails", github: "rails/rails" # Bundle edge Rails instead: gem "rails", github: "rails/rails"
gem "rails", "~> 6.0.0" gem "rails", "~> 6.0.3.1"
# Use postgresql as the database for Active Record # Use postgresql as the database for Active Record
gem "pg", "~> 0.18" gem "pg", "~> 0.18"
# Use Puma as the app server # Use Puma as the app server
@@ -30,9 +30,9 @@ gem "active_storage_base64", "~> 1.0.0"
gem "image_processing", "~> 1.2" gem "image_processing", "~> 1.2"
# Use Amazon Web Services S3 for file uploads in production # Use Amazon Web Services S3 for file uploads in production
gem "aws-sdk-s3", "~> 1.31.0", require: false, group: [:production, :review] gem "aws-sdk-s3", "~> 1.48", require: false, group: [:production, :review]
# Allow AWS API requests to be signed using IAM credentials # Allow AWS API requests to be signed using IAM credentials
gem "aws-sigv4", "~> 1.0.2" gem "aws-sigv4", "~> 1.1"
# Reduces boot times through caching; required in config/boot.rb # Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", ">= 1.1.0", require: false gem "bootsnap", ">= 1.1.0", require: false

View File

@@ -44,71 +44,71 @@ GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
Ascii85 (1.0.3) Ascii85 (1.0.3)
actioncable (6.0.0) actioncable (6.0.3.2)
actionpack (= 6.0.0) actionpack (= 6.0.3.2)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
actionmailbox (6.0.0) actionmailbox (6.0.3.2)
actionpack (= 6.0.0) actionpack (= 6.0.3.2)
activejob (= 6.0.0) activejob (= 6.0.3.2)
activerecord (= 6.0.0) activerecord (= 6.0.3.2)
activestorage (= 6.0.0) activestorage (= 6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
mail (>= 2.7.1) mail (>= 2.7.1)
actionmailer (6.0.0) actionmailer (6.0.3.2)
actionpack (= 6.0.0) actionpack (= 6.0.3.2)
actionview (= 6.0.0) actionview (= 6.0.3.2)
activejob (= 6.0.0) activejob (= 6.0.3.2)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (6.0.0) actionpack (6.0.3.2)
actionview (= 6.0.0) actionview (= 6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
rack (~> 2.0) rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.0.0) actiontext (6.0.3.2)
actionpack (= 6.0.0) actionpack (= 6.0.3.2)
activerecord (= 6.0.0) activerecord (= 6.0.3.2)
activestorage (= 6.0.0) activestorage (= 6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (6.0.0) actionview (6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_storage_base64 (1.0.0) active_storage_base64 (1.0.0)
rails (~> 6.0) rails (~> 6.0)
activejob (6.0.0) activejob (6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (6.0.0) activemodel (6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
activemodel-serializers-xml (1.0.2) activemodel-serializers-xml (1.0.2)
activemodel (> 5.x) activemodel (> 5.x)
activesupport (> 5.x) activesupport (> 5.x)
builder (~> 3.1) builder (~> 3.1)
activerecord (6.0.0) activerecord (6.0.3.2)
activemodel (= 6.0.0) activemodel (= 6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
activeresource (5.1.0) activeresource (5.1.0)
activemodel (>= 5.0, < 7) activemodel (>= 5.0, < 7)
activemodel-serializers-xml (~> 1.0) activemodel-serializers-xml (~> 1.0)
activesupport (>= 5.0, < 7) activesupport (>= 5.0, < 7)
activestorage (6.0.0) activestorage (6.0.3.2)
actionpack (= 6.0.0) actionpack (= 6.0.3.2)
activejob (= 6.0.0) activejob (= 6.0.3.2)
activerecord (= 6.0.0) activerecord (= 6.0.3.2)
marcel (~> 0.3.1) marcel (~> 0.3.1)
activesupport (6.0.0) activesupport (6.0.3.2)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
zeitwerk (~> 2.1, >= 2.1.8) zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.7.0) addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0) public_suffix (>= 2.0.2, < 5.0)
afm (0.2.2) afm (0.2.2)
@@ -117,21 +117,22 @@ GEM
ast (2.4.0) ast (2.4.0)
autoprefixer-rails (9.7.3) autoprefixer-rails (9.7.3)
execjs execjs
aws-eventstream (1.0.3) aws-eventstream (1.1.0)
aws-partitions (1.210.0) aws-partitions (1.337.0)
aws-sdk-core (3.46.2) aws-sdk-core (3.102.1)
aws-eventstream (~> 1.0) aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1.0) aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.0) aws-sigv4 (~> 1.1)
jmespath (~> 1.0) jmespath (~> 1.0)
aws-sdk-kms (1.13.0) aws-sdk-kms (1.35.0)
aws-sdk-core (~> 3, >= 3.39.0) aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.0) aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.31.0) aws-sdk-s3 (1.72.0)
aws-sdk-core (~> 3, >= 3.39.0) aws-sdk-core (~> 3, >= 3.102.1)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.0) aws-sigv4 (~> 1.1)
aws-sigv4 (1.0.3) aws-sigv4 (1.2.1)
aws-eventstream (~> 1, >= 1.0.2)
axlsx (3.0.0.pre) axlsx (3.0.0.pre)
htmlentities (~> 4.3, >= 4.3.4) htmlentities (~> 4.3, >= 4.3.4)
mimemagic (~> 0.3) mimemagic (~> 0.3)
@@ -181,7 +182,7 @@ GEM
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.12.2) coffee-script-source (1.12.2)
concurrent-ruby (1.1.5) concurrent-ruby (1.1.6)
connection_pool (2.2.2) connection_pool (2.2.2)
countries (2.1.4) countries (2.1.4)
i18n_data (~> 0.8.0) i18n_data (~> 0.8.0)
@@ -230,7 +231,7 @@ GEM
hubspot-ruby (0.9.0) hubspot-ruby (0.9.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
httparty (>= 0.10.0) httparty (>= 0.10.0)
i18n (1.8.2) i18n (1.8.3)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n_data (0.8.0) i18n_data (0.8.0)
i18n_yaml_sorter (0.2.0) i18n_yaml_sorter (0.2.0)
@@ -270,22 +271,22 @@ GEM
ruby_dep (~> 1.2) ruby_dep (~> 1.2)
loaf (0.8.1) loaf (0.8.1)
rails (>= 3.2) rails (>= 3.2)
loofah (2.4.0) loofah (2.6.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.1) mail (2.7.1)
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
marcel (0.3.3) marcel (0.3.3)
mimemagic (~> 0.3.2) mimemagic (~> 0.3.2)
method_source (0.9.2) method_source (1.0.0)
mime-types (3.3) mime-types (3.3)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2019.0904) mime-types-data (3.2019.0904)
mimemagic (0.3.3) mimemagic (0.3.5)
mini_magick (4.9.5) mini_magick (4.9.5)
mini_mime (1.0.2) mini_mime (1.0.2)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
minitest (5.14.0) minitest (5.14.1)
monetize (1.9.2) monetize (1.9.2)
money (~> 6.12) money (~> 6.12)
money (6.13.4) money (6.13.4)
@@ -298,8 +299,8 @@ GEM
msgpack (1.3.1) msgpack (1.3.1)
multi_xml (0.6.0) multi_xml (0.6.0)
multipart-post (2.1.1) multipart-post (2.1.1)
nio4r (2.5.1) nio4r (2.5.2)
nokogiri (1.10.7) nokogiri (1.10.9)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
oath (1.1.0) oath (1.1.0)
bcrypt bcrypt
@@ -337,20 +338,20 @@ GEM
rack rack
rack-test (1.1.0) rack-test (1.1.0)
rack (>= 1.0, < 3) rack (>= 1.0, < 3)
rails (6.0.0) rails (6.0.3.2)
actioncable (= 6.0.0) actioncable (= 6.0.3.2)
actionmailbox (= 6.0.0) actionmailbox (= 6.0.3.2)
actionmailer (= 6.0.0) actionmailer (= 6.0.3.2)
actionpack (= 6.0.0) actionpack (= 6.0.3.2)
actiontext (= 6.0.0) actiontext (= 6.0.3.2)
actionview (= 6.0.0) actionview (= 6.0.3.2)
activejob (= 6.0.0) activejob (= 6.0.3.2)
activemodel (= 6.0.0) activemodel (= 6.0.3.2)
activerecord (= 6.0.0) activerecord (= 6.0.3.2)
activestorage (= 6.0.0) activestorage (= 6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
bundler (>= 1.3.0) bundler (>= 1.3.0)
railties (= 6.0.0) railties (= 6.0.3.2)
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.4) rails-controller-testing (1.0.4)
actionpack (>= 5.0.1.x) actionpack (>= 5.0.1.x)
@@ -363,9 +364,9 @@ GEM
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0) rails-html-sanitizer (1.3.0)
loofah (~> 2.3) loofah (~> 2.3)
railties (6.0.0) railties (6.0.3.2)
actionpack (= 6.0.0) actionpack (= 6.0.3.2)
activesupport (= 6.0.0) activesupport (= 6.0.3.2)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.20.3, < 2.0) thor (>= 0.20.3, < 2.0)
@@ -469,7 +470,7 @@ GEM
turbolinks-source (5.2.0) turbolinks-source (5.2.0)
typhoeus (1.3.1) typhoeus (1.3.1)
ethon (>= 0.9.0) ethon (>= 0.9.0)
tzinfo (1.2.6) tzinfo (1.2.7)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (4.1.20) uglifier (4.1.20)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)
@@ -494,9 +495,9 @@ GEM
activesupport (>= 4.2) activesupport (>= 4.2)
rack-proxy (>= 0.6.1) rack-proxy (>= 0.6.1)
railties (>= 4.2) railties (>= 4.2)
websocket-driver (0.7.1) websocket-driver (0.7.2)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.4) websocket-extensions (0.1.5)
will_paginate (3.2.1) will_paginate (3.2.1)
will_paginate-bootstrap4 (0.2.2) will_paginate-bootstrap4 (0.2.2)
will_paginate (~> 3.0, >= 3.0.0) will_paginate (~> 3.0, >= 3.0.0)
@@ -504,7 +505,7 @@ GEM
wkhtmltopdf-heroku (2.12.5.0) wkhtmltopdf-heroku (2.12.5.0)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
zeitwerk (2.2.2) zeitwerk (2.3.1)
PLATFORMS PLATFORMS
ruby ruby
@@ -514,8 +515,8 @@ DEPENDENCIES
activeresource (= 5.1.0) activeresource (= 5.1.0)
acts-as-taggable-on! acts-as-taggable-on!
analytics-ruby analytics-ruby
aws-sdk-s3 (~> 1.31.0) aws-sdk-s3 (~> 1.48)
aws-sigv4 (~> 1.0.2) aws-sigv4 (~> 1.1)
axlsx (~> 3.0.0.pre) axlsx (~> 3.0.0.pre)
axlsx_rails (~> 0.5.2) axlsx_rails (~> 0.5.2)
axlsx_styler (~> 0.2.0) axlsx_styler (~> 0.2.0)
@@ -561,7 +562,7 @@ DEPENDENCIES
rack! rack!
rack-contrib (~> 2.0.1) rack-contrib (~> 2.0.1)
rack-cors rack-cors
rails (~> 6.0.0) rails (~> 6.0.3.1)
rails-controller-testing (~> 1.0.4) rails-controller-testing (~> 1.0.4)
rails-data-migrations (~> 1.2.0) rails-data-migrations (~> 1.2.0)
redcarpet (~> 3.4.0) redcarpet (~> 3.4.0)

View File

@@ -95,14 +95,28 @@ rake i18n:sort
``` ```
## Zoom.us integration ## 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 #### 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

@@ -8,11 +8,16 @@ $(document).on "turbolinks:load", ->
# 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" then @refreshBroadcastVideo(data) when "broadcast_stream_update"
when "stream_recording_ready" then @showBroadcastRecordings(data) return unless document.querySelector("meta[name=broadcast-token][current=true][content='#{broadcastToken}']")
when "file_upload_update" then @refreshBroadcastFilesTab(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

View File

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

View File

@@ -51,10 +51,8 @@ $(document).on("turbolinks:load", function() {
$("[data-behavior=guardian-photo-preview]").each(function(index, element) { $("[data-behavior=guardian-photo-preview]").each(function(index, element) {
App.PhotoPreview.init(element); App.PhotoPreview.init(element);
}); });
$("[data-behavior=take-person-photo]").click(function(e) { $("[data-behavior=trigger-click]").click(function(e) {
$("[data-ujs-target=person-photo-input]").trigger("click"); const target = $(this).data("target");
}); $(target).trigger("click");
$("[data-behavior=take-guardian-photo]").click(function(e) {
$("[data-ujs-target=guardian-photo-input]").trigger("click");
}); });
}); });

View File

@@ -1,24 +0,0 @@
$(document).on("click", "[data-behavior=play_recording]", function() {
if ($(this).hasClass('active')){
return false;
}
var playback_url = $(this).attr("data-playback-url")
$("#broadcast_video").empty();
new Clappr.Player({
parentId: '#broadcast_video',
source: playback_url,
width: '100%',
height: '100%',
autoPlay: true
});
$(".dropdown-menu").children().removeClass('active');
$(".dropdown-menu").children().children('i').remove();
$(this).siblings().removeClass('active');
$(this).siblings().children("i").remove();
$(this).addClass('active');
$(this).prepend('<i class="fa fa-check">&nbsp;</i>');
});

View File

@@ -0,0 +1,26 @@
$(document).on("click", "[data-behavior=play_recording]", function() {
if ($(this).hasClass('active')){
return false;
}
console.warn('Play prev : ', playback_url);
var playback_url = $(this).attr("data-playback-url")
$("#broadcast_video").empty();
new Clappr.Player({
<%= "baseUrl: 'http://cdn.clappr.io/latest'," if Rails.env.test? %>
parentId: '#broadcast_video',
source: playback_url,
width: '100%',
height: '100%',
autoPlay: true
});
$(".dropdown-menu").children().removeClass('active');
$(".dropdown-menu").children().children('i').remove();
$(this).siblings().removeClass('active');
$(this).siblings().children("i").remove();
$(this).addClass('active');
$(this).prepend('<i class="fa fa-check">&nbsp;</i>');
});

View File

@@ -0,0 +1,13 @@
$(document).on("turbolinks:load", function() {
$("[data-behavior=update-required-status]").click(function(e) {
const required = !!($(this)[0] && $(this)[0].checked);
$("[data-required-tag=guardian]").each(function(index, element) {
const labelForField = element.previousSibling;
element.required = required;
labelForField.classList.add("required");
});
});
});

View File

@@ -14,6 +14,7 @@ $red: #F9002B;
$green: #51B61B; $green: #51B61B;
$teal: #32C498; $teal: #32C498;
$purple: #5139EE; $purple: #5139EE;
$yellow: #F9BE1B;
$dark: $gray-900; $dark: $gray-900;
$success: $teal; $success: $teal;
$link-color: $body-color; $link-color: $body-color;

View File

@@ -37,14 +37,14 @@ label {
&.release-me { &.release-me {
span:last-child { span:last-child {
background-color: $teal; background-color: $teal;
color: $body-color; color: $white;
} }
} }
&.direct-me { &.direct-me {
span:last-child { span:last-child {
background-color: $green; background-color: $green;
color: $body-color; color: $white;
} }
} }
@@ -58,7 +58,14 @@ label {
&.deliver-me { &.deliver-me {
span:last-child { span:last-child {
background-color: $purple; background-color: $purple;
color: white; color: $white;
}
}
&.task-me {
span:last-child {
background-color: $yellow;
color: $white;
} }
} }

View File

@@ -31,7 +31,7 @@ u {
} }
.page { .page {
page-break-before: always; page-break-before: always;
} }
.logo { .logo {
@@ -44,6 +44,14 @@ 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

@@ -17,7 +17,7 @@ class AccountsController < ApplicationController
if sign_in(user) if sign_in(user)
TrackAnalyticsJob.perform_later(user, user.primary_account, :track_guest_sign_up, user_agent: request.user_agent, user_ip: request.remote_ip) TrackAnalyticsJob.perform_later(user, user.primary_account, :track_guest_sign_up, user_agent: request.user_agent, user_ip: request.remote_ip)
SubmitHubspotFormJob.perform_later(user.email, account.name, i_m_interested_in: user.interested_product_name) SubmitHubspotFormJob.perform_later(user.first_name, user.last_name, user.email, account.name, i_m_interested_in: user.interested_product_name)
redirect_to signed_in_root_path redirect_to signed_in_root_path
else else
redirect_to new_session_path, alert: t(".notice") redirect_to new_session_path, alert: t(".notice")

View File

@@ -0,0 +1,36 @@
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 show
@files = @task_request.files.paginate(page: params[:page])
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

@@ -17,7 +17,9 @@ class Api::ApiController < ActionController::Base
def return_error(exception) def return_error(exception)
raise exception if Rails.env.test? raise exception if Rails.env.test?
logger.error "==Handled=======" Raven.capture_exception(exception)
logger.error "==Handled======"
logger.error exception.message logger.error exception.message
logger.error exception.backtrace.join("\n") logger.error exception.backtrace.join("\n")
logger.error "==Handled=======" logger.error "==Handled======="

View File

@@ -19,5 +19,11 @@ class Api::AppearanceReleasesController < Api::ReleasesController
guardian_photo[:io] = StringIO.new(Base64.decode64(guardian_photo[:io])) guardian_photo[:io] = StringIO.new(Base64.decode64(guardian_photo[:io]))
release.guardian_photo.attach(io: guardian_photo[:io], filename: guardian_photo[:filename]) release.guardian_photo.attach(io: guardian_photo[:io], filename: guardian_photo[:filename])
end end
guardian_2_photo = release_create_params[:guardian_2_photo]
if guardian_2_photo
guardian_2_photo[:io] = StringIO.new(Base64.decode64(guardian_2_photo[:io]))
release.guardian_2_photo.attach(io: guardian_2_photo[:io], filename: guardian_2_photo[:filename])
end
end end
end end

View File

@@ -24,8 +24,12 @@ class Api::BroadcastsController < Api::ApiController
def update def update
file_params.each do |file| file_params.each do |file|
file[:io] = StringIO.new(Base64.decode64(file[:io])) if file.is_a?(String)
@broadcast.files.attach(io: file[:io], filename: file[:filename]) @broadcast.files.attach(file)
else
file[:io] = StringIO.new(Base64.decode64(file[:io]))
@broadcast.files.attach(file.to_h.symbolize_keys)
end
end end
@broadcast.save! @broadcast.save!

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

@@ -103,10 +103,16 @@ class Api::ReleasesController < Api::ApiController
if ["appearance_release", "talent_release"].include?(name) if ["appearance_release", "talent_release"].include?(name)
has_many :guardian_photos do has_many :guardian_photos do
data do data do
[@object.guardian_photo.try(:attachment)].compact [
@object.guardian_photo.try(:attachment),
@object.guardian_2_photo.try(:attachment)
].compact
end end
meta do meta do
{ count: @object.try(:guardian_photo).try(:attached?) ? 1 : 0 } { count:
(@object.try(:guardian_photo).try(:attached?) ? 1 : 0) +
(@object.try(:guardian_2_photo).try(:attached?) ? 1 : 0)
}
end end
end end
end end
@@ -170,7 +176,7 @@ class Api::ReleasesController < Api::ApiController
def release_create_params def release_create_params
parameters = params.require(model_name).permit! parameters = params.require(model_name).permit!
keys = model_constant.new.attributes.keys + [:guardian_photo, :person_photo, :photos, :signature, :signature_base64, :file_infos_attributes] keys = model_constant.new.attributes.keys + [:guardian_photo, :guardian_2_photo, :person_photo, :photos, :signature, :signature_base64, :file_infos_attributes]
parameters[:signature_base64] = parameters[:signature] parameters[:signature_base64] = parameters[:signature]
parameters = parameters.slice(*keys).except(:created_at, :updated_at, :id, :user_id, :signature) parameters = parameters.slice(*keys).except(:created_at, :updated_at, :id, :user_id, :signature)
parameters parameters

View File

@@ -17,5 +17,11 @@ class Api::TalentReleasesController < Api::ReleasesController
guardian_photo[:io] = StringIO.new(Base64.decode64(guardian_photo[:io])) guardian_photo[:io] = StringIO.new(Base64.decode64(guardian_photo[:io]))
release.guardian_photo.attach(io: guardian_photo[:io], filename: guardian_photo[:filename]) release.guardian_photo.attach(io: guardian_photo[:io], filename: guardian_photo[:filename])
end end
guardian_2_photo = release_create_params[:guardian_2_photo]
if guardian_2_photo
guardian_2_photo[:io] = StringIO.new(Base64.decode64(guardian_2_photo[:io]))
release.guardian_2_photo.attach(io: guardian_2_photo[:io], filename: guardian_2_photo[:filename])
end
end end
end end

View File

@@ -5,6 +5,8 @@ class Api::UserTokenController < Knock::AuthTokenController
# Catch exception and return JSON-formatted error # Catch exception and return JSON-formatted error
def return_error(exception) def return_error(exception)
Raven.capture_exception(exception)
logger.error "==Handled=======" logger.error "==Handled======="
logger.error exception.message logger.error exception.message
logger.error exception.backtrace.join("\n") logger.error exception.backtrace.join("\n")

View File

@@ -3,7 +3,6 @@
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]
@@ -11,24 +10,16 @@ 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
attachments.each do |attachment| MatchAppearanceReleasesJob.perform_later(@project, attachments)
create_imported_appearance_release attachment notice_message = t 'appearance_releases.create.matching_started'
end redirect_to [@project, :appearance_releases], notice: notice_message
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
@@ -45,45 +36,7 @@ class AppearanceReleaseImportsController < ApplicationController
params.require(:attachments) params.require(:attachments)
end end
def build_appearance_release(params = {}) def acceptable_extensions
authorize appearance_releases.build(params) AppearanceRelease.acceptable_import_file_extensions
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

@@ -77,9 +77,43 @@ class AppearanceReleasesController < ApplicationController
results results
end end
def person_params
%i[
person_first_name
person_last_name
person_phone
person_email
person_photo
person_address_street1
]
end
def guardian_params
%i[
guardian_first_name
guardian_last_name
guardian_phone
guardian_email
guardian_photo
guardian_address_street1
]
end
def second_guardian_params
%i[
guardian_2_first_name
guardian_2_last_name
guardian_2_phone
guardian_2_email
guardian_2_photo
guardian_2_address_street1
]
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, :minor, params.require(:appearance_release).permit(person_params,
:person_address, :person_first_name, :person_last_name, :person_phone, :person_email, :person_photo, guardian_params, second_guardian_params,
:contract, :minor,
:applicable_medium_id, :applicable_medium_text, :applicable_medium_id, :applicable_medium_text,
:territory_id, :territory_text, :territory_id, :territory_text,
:term_id, :term_text, :person_date_of_birth, :term_id, :term_text, :person_date_of_birth,

View File

@@ -5,6 +5,7 @@ class BroadcastsController < ApplicationController
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]
before_action :set_multi_view_broadcasts, only: [:show] before_action :set_multi_view_broadcasts, only: [:show]
before_action :show_splash_screen, only: :index
def index def index
@broadcasts = filtered_broadcasts.order_by_recent.paginate(page: params[:page]) @broadcasts = filtered_broadcasts.order_by_recent.paginate(page: params[:page])
@@ -49,6 +50,10 @@ class BroadcastsController < ApplicationController
private private
def show_splash_screen
render :splash if broadcasts.count.zero?
end
def broadcast_params def broadcast_params
params.require(:broadcast).permit(:name, files: []) params.require(:broadcast).permit(:name, files: [])
end end

View File

@@ -0,0 +1,13 @@
module MiscReleaseContext
extend ActiveSupport::Concern
def misc_releases
policy_scope(MiscRelease)
end
def set_misc_release
misc_release_id = params[:misc_release_id] || params[:id]
@misc_release = authorize misc_releases.find(misc_release_id)
end
end

View File

@@ -7,6 +7,7 @@ class ContractTemplatesController < ApplicationController
before_action :set_project, except: [:destroy] before_action :set_project, except: [:destroy]
before_action :set_contract_template, only: [:destroy] before_action :set_contract_template, only: [:destroy]
before_action :show_splash_screen, only: :index
def index def index
@contract_templates = contract_templates.non_archived.order_by_name.paginate(page: params[:page]) @contract_templates = contract_templates.non_archived.order_by_name.paginate(page: params[:page])
@@ -38,6 +39,10 @@ class ContractTemplatesController < ApplicationController
private private
def show_splash_screen
render :splash if contract_templates.non_archived.count.zero?
end
def set_contract_template def set_contract_template
@contract_template = authorize contract_templates.find(params[:id]) @contract_template = authorize contract_templates.find(params[:id])
end end
@@ -61,7 +66,15 @@ 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,
:question_11_text, :question_12_text,
:question_13_text, :question_14_text,
:question_15_text)
end end
def download_attributes def download_attributes

View File

@@ -48,8 +48,10 @@ class ContractsController < ApplicationController
# Native release contracts must be generated on-the-fly; non-native releases have a contract attachment # Native release contracts must be generated on-the-fly; non-native releases have a contract attachment
if releasable.native? if releasable.native?
send_file contract.to_pdf, download_attributes send_file contract.to_pdf, download_attributes
else elsif policy(contract).show?
redirect_to releasable.contract.service_url redirect_to releasable.contract.service_url
else
raise Pundit::NotAuthorizedError
end end
end end
end end

View File

@@ -0,0 +1,40 @@
class MiscReleasesController < ApplicationController
include ProjectContext, MiscReleaseContext
before_action :set_project, only: [:index]
before_action :set_misc_release, only: [:destroy]
include ProjectLayout
def index
@misc_releases = filtered_misc_releases.order_by_recent.paginate(page: params[:page])
end
def destroy
@project = @misc_release.project
if @misc_release.destroy
redirect_to [@project, :misc_releases], alert: t(".alert")
end
end
private
def misc_releases
if @project
policy_scope(@project.misc_releases)
else
policy_scope(MiscRelease)
end
end
def filtered_misc_releases
results = misc_releases
if params[:query].present?
results = results.search(params[:query])
end
results
end
end

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 medical_release misc_release video_analysis)
end end
def project_params_with_current_account def project_params_with_current_account

View File

@@ -39,11 +39,60 @@ class Public::AppearanceReleasesController < Public::BaseController
authorize appearance_releases.build(params) authorize appearance_releases.build(params)
end 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 guardian_params
%i[
guardian_first_name
guardian_last_name
guardian_phone
guardian_email
guardian_photo
guardian_address_street1
guardian_address_street2
guardian_address_city
guardian_address_state
guardian_address_zip
guardian_address_country
]
end
def second_guardian_params
%i[
guardian_2_first_name
guardian_2_last_name
guardian_2_phone
guardian_2_email
guardian_2_photo
guardian_2_address_street1
guardian_2_address_street2
guardian_2_address_city
guardian_2_address_state
guardian_2_address_zip
guardian_2_address_country
]
end
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_params, guardian_params,
:guardian_address, :guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_photo, :minor, second_guardian_params,
:signature_base64, :person_date_of_birth, :minor, :signature_base64,
:locale, :contract_template,) :person_date_of_birth,
:locale, :contract_template)
end end
def appearance_release_params_with_locale def appearance_release_params_with_locale

View File

@@ -37,6 +37,10 @@ class Public::BroadcastsController < Public::BaseController
def set_broadcast def set_broadcast
@broadcast = Broadcast.find_by_token(params[:token]) @broadcast = Broadcast.find_by_token(params[:token])
unless @broadcast.present?
redirect_to [:new, :session], alert: t(".alert")
end
end end
class MultiViewBroadcast class MultiViewBroadcast

View File

@@ -45,25 +45,67 @@ class Public::MedicalReleasesController < Public::BaseController
.require(:medical_release) .require(:medical_release)
.permit( .permit(
person_params, person_params,
guardian_params,
second_guardian_params,
:minor,
:signature_base64, :signature_base64,
:locale, :locale,
:contract_template, :contract_template,
photos: [], :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,
:question_11_answer, :question_12_answer,
:question_13_answer, :question_14_answer,
:question_15_answer, photos: [],
) )
end end
def person_params def person_params
[ %i[
:person_first_name, person_first_name
:person_last_name, person_last_name
:person_phone, person_phone
:person_email, person_email
:person_address_street1, person_address_street1
:person_address_street2, person_address_street2
:person_address_city, person_address_city
:person_address_state, person_address_state
:person_address_zip, person_address_zip
:person_address_country, person_address_country
]
end
def guardian_params
%i[
guardian_first_name
guardian_last_name
guardian_phone
guardian_email
guardian_photo
guardian_address_street1
guardian_address_street2
guardian_address_city
guardian_address_state
guardian_address_zip
guardian_address_country
]
end
def second_guardian_params
%i[
guardian_2_first_name
guardian_2_last_name
guardian_2_phone
guardian_2_email
guardian_2_photo
guardian_2_address_street1
guardian_2_address_street2
guardian_2_address_city
guardian_2_address_state
guardian_2_address_zip
guardian_2_address_country
] ]
end end

View File

@@ -0,0 +1,120 @@
class Public::MiscReleasesController < Public::BaseController
before_action :set_account, :set_project, :set_contract_template
def new
@misc_release = build_misc_release
end
def create
@misc_release = build_misc_release(misc_release_params_with_locale_and_contract_template)
if @misc_release.save(context: :native)
if @misc_release.contract_template.present?
AttachContractToReleasableJob.perform_later(@misc_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 misc_releases
policy_scope(@project.misc_releases)
end
def build_misc_release(params = {})
authorize misc_releases.build(params)
end
def misc_release_params
params
.require(:misc_release)
.permit(
person_params,
guardian_params,
questionnaire_params,
:signature_base64,
:locale,
:contract_template,
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 guardian_params
[
:guardian_first_name,
:guardian_last_name,
:guardian_phone,
:guardian_email,
:minor,
:guardian_address_street1,
:guardian_address_street2,
:guardian_address_city,
:guardian_address_state,
:guardian_address_zip,
:guardian_address_country,
:guardian_photo
]
end
def questionnaire_params
[
: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,
:question_11_answer,
:question_12_answer,
:question_13_answer,
:question_14_answer,
:question_15_answer,
]
end
def misc_release_params_with_locale
misc_release_params.merge(locale: I18n.locale)
end
def misc_release_params_with_locale_and_contract_template
misc_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: MiscRelease.to_s, account: @account, user_agent: request.user_agent, user_ip: request.remote_ip)
end
end

View File

@@ -45,42 +45,59 @@ class Public::TalentReleasesController < Public::BaseController
.permit( .permit(
person_params, person_params,
guardian_params, guardian_params,
second_guardian_params,
:signature_base64, :signature_base64,
:locale, :locale,
:contract_template, :contract_template,
photos: [], photos: []
) )
end end
def person_params def person_params
[ %i[
:person_first_name, person_first_name
:person_last_name, person_last_name
:person_phone, person_phone
:person_email, person_email
:person_address_street1, person_address_street1
:person_address_street2, person_address_street2
:person_address_city, person_address_city
:person_address_state, person_address_state
:person_address_zip, person_address_zip
:person_address_country, person_address_country
] ]
end end
def guardian_params def guardian_params
[ %i[
:guardian_first_name, guardian_first_name
:guardian_last_name, guardian_last_name
:guardian_phone, guardian_phone
:guardian_email, guardian_email
:minor, minor
:guardian_address_street1, guardian_address_street1
:guardian_address_street2, guardian_address_street2
:guardian_address_city, guardian_address_city
:guardian_address_state, guardian_address_state
:guardian_address_zip, guardian_address_zip
:guardian_address_country, guardian_address_country
:guardian_photo, guardian_photo
]
end
def second_guardian_params
%i[
guardian_2_first_name
guardian_2_last_name
guardian_2_phone
guardian_2_email
guardian_2_address_street1
guardian_2_address_street2
guardian_2_address_city
guardian_2_address_state
guardian_2_address_zip
guardian_2_address_country
guardian_2_photo
] ]
end end

View File

@@ -11,7 +11,9 @@ class ReleaseTemplateImportsController < ApplicationController
templates = [] templates = []
filtered_contract_templates.each do |contract_template| filtered_contract_templates.each do |contract_template|
next if contract_template.duplicated? || contract_template.project == @project next if contract_template.duplicated? ||
contract_template.archived? ||
contract_template.project == @project
already_imported = contract_template.duplicates.non_archived.pluck(:project_id).include?(@project.id) already_imported = contract_template.duplicates.non_archived.pluck(:project_id).include?(@project.id)
templates << OpenStruct.new(template: contract_template, already_imported?: already_imported) templates << OpenStruct.new(template: contract_template, already_imported?: already_imported)

View File

@@ -60,9 +60,14 @@ class StreamNotificationsController < ApplicationController
def set_broadcast def set_broadcast
if notification_type == "video.asset.static_renditions.ready" if notification_type == "video.asset.static_renditions.ready"
live_stream_id = notification.dig(:stream_notification, :data, :live_stream_id) live_stream_id = notification.dig(:stream_notification, :data, :live_stream_id)
@broadcast = Broadcast.find_by!(stream_uid: live_stream_id) @broadcast = Broadcast.find_by(stream_uid: live_stream_id)
else else
@broadcast = Broadcast.find_by!(stream_uid: notification_object_id) @broadcast = Broadcast.find_by(stream_uid: notification_object_id)
end
if @broadcast.nil?
logger.info "Ignoring broadcast from other environment. Type = #{notification_type}. Id = #{live_stream_id} / #{notification_object_id}"
head :ok
end end
end end

View File

@@ -61,15 +61,67 @@ class TalentReleasesController < ApplicationController
end end
end end
def person_params
%i[
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 guardian_params
%i[
guardian_first_name
guardian_last_name
guardian_phone
guardian_email
minor
guardian_address_street1
guardian_address_street2
guardian_address_city
guardian_address_state
guardian_address_zip
guardian_address_country
guardian_photo
]
end
def second_guardian_params
%i[
guardian_2_first_name
guardian_2_last_name
guardian_2_phone
guardian_2_email
guardian_2_address_street1
guardian_2_address_street2
guardian_2_address_city
guardian_2_address_state
guardian_2_address_zip
guardian_2_address_country
guardian_2_photo
]
end
def talent_release_params def talent_release_params
params.require(:talent_release).permit( params.require(:talent_release).permit(person_params,
:person_first_name, :person_last_name, :person_phone, :guardian_photo, :person_email, guardian_params,
:person_address_street1, :person_address_street2, :person_address_city, :person_address_state, :person_address_zip, :person_address_country, second_guardian_params,
:guardian_first_name, :guardian_last_name, :guardian_phone, :guardian_email, :minor, :contract, { photos: [] },
:guardian_address_street1, :guardian_address_street2, :guardian_address_city, :guardian_address_state, :guardian_address_zip, :guardian_address_country, :applicable_medium_id,
:contract, { photos: [] }, :applicable_medium_text,
:applicable_medium_id, :applicable_medium_text, :territory_id, :territory_text, :term_id, :term_text, :restriction_id, :restriction_text :territory_id,
) :territory_text,
:term_id,
:term_text,
:restriction_id,
:restriction_text)
end end
def build_talent_release(attrs = {}) def build_talent_release(attrs = {})

View File

@@ -0,0 +1,81 @@
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]
before_action :show_splash_screen, only: :index
def index
@task_requests = task_requests.order_by_recent.paginate(page: params[:page])
end
def new
end
def create
@task_request.attributes = task_request_params_with_email
if @task_request.save
log_create_analytics
taskme_url = url_for([:admin, @task_request])
SubmitHubspotTaskRequestFormJob.perform_later(@task_request.user_email, taskme_url)
else
render :new
end
end
def show
@files = @task_request.files.paginate(page: params[:page])
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 show_splash_screen
render :splash if task_requests.count.zero?
end
def task_request_params
params.require(:task_request).permit(:description, :deadline, :time_allowed, :additional_notes, files: [])
end
def task_request_params_with_email
task_request_params.merge(user_email: Current.user.email)
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

@@ -0,0 +1,19 @@
class TasksController < ApplicationController
before_action :set_project
include ProjectLayout
def index
@tasks = task_requests.completed.order_by_recent.paginate(page: params[:page])
end
private
def set_project
@project = policy_scope(Project).find(params[:project_id])
end
def task_requests
authorize policy_scope(@project.task_requests)
end
end

View File

@@ -3,6 +3,7 @@ class VideosController < ApplicationController
before_action :set_project, only: [:index, :new, :create, :landing] before_action :set_project, only: [:index, :new, :create, :landing]
before_action :set_video, only: [:edit, :update] before_action :set_video, only: [:edit, :update]
before_action :show_splash_screen, only: :index
def landing def landing
authorize Video, :new? authorize Video, :new?
@@ -60,6 +61,10 @@ class VideosController < ApplicationController
private private
def show_splash_screen
render :splash if videos.count.zero?
end
def set_project def set_project
@project = policy_scope(Project).find(params[:project_id]) @project = policy_scope(Project).find(params[:project_id])
end end

View File

@@ -7,8 +7,8 @@ module DescriptionListHelper
safe_join(tags) safe_join(tags)
end end
def description_list_pair_for(record, attribute, append: nil) def description_list_pair_for(record, attribute, append: nil, custom_label: nil)
term = translation_for(record, attribute) term = custom_label.nil? ? translation_for(record, attribute) : custom_label
definition = record.send(attribute) definition = record.send(attribute)
description_list_pair(term, definition, append: append) description_list_pair(term, definition, append: append)

View File

@@ -2,7 +2,7 @@ module DropzoneHelper
def dropzone_placeholder_message_for(releasable) def dropzone_placeholder_message_for(releasable)
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" '(Optional) To add the licensed photos or videos ("Property") to this release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse photos and connect to Camera'
when "material_release" when "material_release"
t 'material_releases.form.photos.dropzone_label' t 'material_releases.form.photos.dropzone_label'
when "music_release" when "music_release"
@@ -11,6 +11,8 @@ module DropzoneHelper
t 'location_releases.form.photos.dropzone_label' 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"
when "task_request"
"To Add Files for the Task:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files"
else else
"To Add Photos to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse photos and connect to Camera" "To Add Photos to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse photos and connect to Camera"
end end

View File

@@ -13,10 +13,13 @@ module WordmarkHelper
css += options[:class].to_s css += options[:class].to_s
content_tag(:div, class: css) do content_tag(:div, class: css) do
safe_join [ elements = [
content_tag(:span, t("shared.#{product_name}")), content_tag(:span, t("shared.#{product_name}")),
content_tag(:span, t("shared.me")) content_tag(:span, t("shared.me"))
] ]
prefix = options[:prefix]
elements.unshift content_tag(:span, "#{prefix} ") unless prefix.blank?
safe_join elements
end end
end end
end end

View File

@@ -1,5 +1,6 @@
$(document).on("turbolinks:load", () => { $(document).on("turbolinks:load", () => {
$('.datepicker-control').datepicker({ $('.datepicker-control').datepicker({
format: "yyyy-mm-dd" format: "yyyy-mm-dd",
todayHighlight: true
}); });
}); });

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

@@ -1,12 +1,14 @@
class SubmitHubspotFormJob < ApplicationJob class SubmitHubspotFormJob < ApplicationJob
queue_as :default queue_as :default
def perform(email, company_name, additional_params = {}) def perform(first_name, last_name, email, company_name, additional_params = {})
hubspot_form_guid = ENV["HUBSPOT_FORM_GUID"] hubspot_form_guid = ENV["HUBSPOT_FORM_GUID"]
return unless hubspot_form_guid.present? return unless hubspot_form_guid.present?
submission_params = { submission_params = {
email: email, first_name: first_name,
last_name: last_name,
email: email,
company: company_name company: company_name
}.merge(additional_params) }.merge(additional_params)

View File

@@ -0,0 +1,18 @@
class SubmitHubspotTaskRequestFormJob < ApplicationJob
queue_as :default
def perform(user_email, taskme_url)
hubspot_task_request_form_guid = ENV["HUBSPOT_TASK_REQUEST_FORM_GUID"]
return unless hubspot_task_request_form_guid.present?
submission_params = {
email: user_email,
taskme_url: taskme_url
}
form = Hubspot::Form.new("guid" => hubspot_task_request_form_guid)
is_form_sumitted = form.submit(submission_params)
raise StandardError.new "Failed to submit the task request hubspot form data: #{is_form_sumitted}" unless is_form_sumitted
end
end

View File

@@ -54,8 +54,11 @@ 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),
TaskRequest.where(project: projects),
ZoomMeeting.where(project: projects), ZoomMeeting.where(project: projects),
MedicalRelease.where(project: projects), MedicalRelease.where(project: projects),
MiscRelease.where(project: projects),
MatchingRequest.where(project: projects),
self self
])).sum(:byte_size).to_f ])).sum(:byte_size).to_f
end end
@@ -80,6 +83,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 taskme_enabled?
ENV["TASKME_ENABLED"] && (plan_uid.to_s == "me_suite" || plan_uid.to_s == "taskme")
end
def plan_name def plan_name
case plan_uid.to_s case plan_uid.to_s
when "deliverme" when "deliverme"
@@ -88,6 +95,8 @@ class Account < ApplicationRecord
"DirectME" "DirectME"
when "releaseme" when "releaseme"
"ReleaseME" "ReleaseME"
when "taskme"
"TaskME"
when "me_suite" when "me_suite"
"ME Suite" "ME Suite"
end end

View File

@@ -12,10 +12,46 @@ class AppearanceRelease < ApplicationRecord
include Taggable include Taggable
include PersonName include PersonName
include GuardianPhotoable include GuardianPhotoable
include SecondGuardianPhotoable
include GuardianName include GuardianName
include SecondGuardianName
has_one_attached :person_photo 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]
]
composed_of :guardian_address,
class_name: 'Address',
mapping: [
%w[guardian_address_street1 street1],
%w[guardian_address_street2 street2],
%w[guardian_address_city city],
%w[guardian_address_state state],
%w[guardian_address_zip zip],
%w[guardian_address_country country]
]
composed_of :guardian_2_address,
class_name: 'Address',
mapping: [
%w[guardian_2_address_street1 street1],
%w[guardian_2_address_street2 street2],
%w[guardian_2_address_city city],
%w[guardian_2_address_state state],
%w[guardian_2_address_zip zip],
%w[guardian_2_address_country country]
]
# These validations apply to all releases # These validations apply to all releases
validates :person_email, email: true, allow_blank: true validates :person_email, email: true, allow_blank: true
validates :person_first_name, :person_last_name, presence: true validates :person_first_name, :person_last_name, presence: true
@@ -39,6 +75,7 @@ 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
@@ -70,7 +107,18 @@ class AppearanceRelease < ApplicationRecord
scope :having_no_person_photo, -> { left_joins(:person_photo_attachment).group(:id).having('COUNT(active_storage_attachments) = 0') } 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}%") } 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 # All releases must respond to the following messages
def name def name
@@ -97,6 +145,10 @@ class AppearanceRelease < ApplicationRecord
true true
end end
def second_guardian_present?
self.guardian_2_first_name.present?
end
def contract_file_name def contract_file_name
"#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime('%Y.%m.%d')}_#{release_number}_#{filename_suffix.parameterize}" "#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime('%Y.%m.%d')}_#{release_number}_#{filename_suffix.parameterize}"
end end

View File

@@ -8,7 +8,7 @@ class BlankContract
end end
def to_pdf 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}") kit.to_file("tmp/#{filename}")
end 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

@@ -0,0 +1,20 @@
module SecondGuardianName
extend ActiveSupport::Concern
included do
def guardian_2_name
"#{guardian_2_first_name} #{guardian_2_last_name}".titleize
end
def guardian_2_name=(value)
if value.include?(' ')
split = value.split(" ", 2)
self.guardian_2_first_name = split.first
self.guardian_2_last_name = split.last
else
self.guardian_2_first_name = value
self.guardian_2_last_name = "(Not Given)"
end
end
end
end

View File

@@ -0,0 +1,9 @@
module SecondGuardianPhotoable
extend ActiveSupport::Concern
included do
has_one_attached :guardian_2_photo
validates :guardian_2_photo, content_type: ["image/png", "image/jpeg"]
end
end

View File

@@ -29,6 +29,10 @@ class Contract
} }
end end
def medical_release?
@releasable.instance_of?(MedicalRelease)
end
private private
def contract_template def contract_template

View File

@@ -5,6 +5,8 @@ class ContractTemplate < ApplicationRecord
include Syncable include Syncable
include PgSearch include PgSearch
NUMBER_OF_CUSTOM_FIELDS = 15
belongs_to :project belongs_to :project
belongs_to :parent, class_name: 'ContractTemplate', optional: true belongs_to :parent, class_name: 'ContractTemplate', optional: true
has_many :duplicates, class_name: 'ContractTemplate', foreign_key: 'parent_id' has_many :duplicates, class_name: 'ContractTemplate', foreign_key: 'parent_id'
@@ -14,6 +16,7 @@ class ContractTemplate < ApplicationRecord
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 has_many :medical_releases, dependent: :restrict_with_error
has_many :misc_releases, dependent: :restrict_with_error
monetize :fee_cents monetize :fee_cents
has_rich_text :body has_rich_text :body
@@ -51,7 +54,15 @@ class ContractTemplate < ApplicationRecord
parent.present? parent.present?
end end
def archived?
archived_at.present?
end
def archive def archive
update(archived_at: Time.zone.now) update(archived_at: Time.zone.now)
end end
def has_questionnaire?
(1..NUMBER_OF_CUSTOM_FIELDS).any? { |n| public_send("question_#{n}_text").presence }
end
end end

View File

@@ -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 { |_, v| v.blank? } }.reject { |k, v| v.blank? && k != :ids_to_images }
end end
private private

View File

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

View File

@@ -7,16 +7,44 @@ class MedicalRelease < ApplicationRecord
include Signable include Signable
include Syncable include Syncable
include PersonName include PersonName
include GuardianPhotoable
include SecondGuardianPhotoable
include GuardianName
include SecondGuardianName
composed_of :person_address, NUMBER_OF_CUSTOM_FIELDS = 15
composed_of :person_address,
class_name: "Address", class_name: "Address",
mapping: [ mapping: [
%w(person_address_street1 street1), %w[person_address_street1 street1],
%w(person_address_street2 street2), %w[person_address_street2 street2],
%w(person_address_city city), %w[person_address_city city],
%w(person_address_state state), %w[person_address_state state],
%w(person_address_zip zip), %w[person_address_zip zip],
%w(person_address_country country) %w[person_address_country country]
]
composed_of :guardian_address,
class_name: 'Address',
mapping: [
%w[guardian_address_street1 street1],
%w[guardian_address_street2 street2],
%w[guardian_address_city city],
%w[guardian_address_state state],
%w[guardian_address_zip zip],
%w[guardian_address_country country]
]
composed_of :guardian_2_address,
class_name: 'Address',
mapping: [
%w[guardian_2_address_street1 street1],
%w[guardian_2_address_street2 street2],
%w[guardian_2_address_city city],
%w[guardian_2_address_state state],
%w[guardian_2_address_zip zip],
%w[guardian_2_address_country country]
] ]
def self.face_photo_acceptable_content_types def self.face_photo_acceptable_content_types
@@ -26,9 +54,16 @@ class MedicalRelease < ApplicationRecord
# These validations apply to all releases # These validations apply to all releases
validates :person_first_name, :person_last_name, presence: true validates :person_first_name, :person_last_name, presence: true
validates :person_email, email: true, allow_blank: true validates :person_email, email: true, allow_blank: true
validate :valid_answers
acts_as_taggable_on :internal_tags, :tags acts_as_taggable_on :internal_tags, :tags
# These validations apply to releases being signed by a minor
with_options if: :minor? do
validates :guardian_email, email: true, allow_blank: true
validates :guardian_2_email, email: true, allow_blank: true
end
# These validations apply to releases created natively by the system (i.e. not imported from elsewhere) # These validations apply to releases created natively by the system (i.e. not imported from elsewhere)
with_options on: :native do with_options on: :native do
validates :signature, attached: true validates :signature, attached: true
@@ -61,11 +96,18 @@ class MedicalRelease < ApplicationRecord
false false
end end
def minor?
false
end
def contract_file_name def contract_file_name
"#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime("%Y.%m.%d")}_#{release_number}_#{filename_suffix.parameterize}" "#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime("%Y.%m.%d")}_#{release_number}_#{filename_suffix.parameterize}"
end end
private
def valid_answers
(1..ContractTemplate::NUMBER_OF_CUSTOM_FIELDS).each do |index|
if contract_template && contract_template["question_#{index}_text"].present? &&
public_send("question_#{index}_answer").blank?
errors.add("question_#{index}", I18n.t('medical_releases.custom_validation_errors.question_answer_is_required'))
end
end
end
end end

View File

@@ -0,0 +1,88 @@
class MiscRelease < ApplicationRecord
include Contractable
include Notable
include Photoable
include Releasable
include Searchable
include Signable
include Syncable
include PersonName
include GuardianName
include GuardianPhotoable
NUMBER_OF_CUSTOM_FIELDS = 15
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)
]
composed_of :guardian_address,
class_name: "Address",
mapping: [
%w(guardian_address_street1 street1),
%w(guardian_address_street2 street2),
%w(guardian_address_city city),
%w(guardian_address_state state),
%w(guardian_address_zip zip),
%w(guardian_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
with_options if: :minor? do
validates :guardian_first_name, :guardian_last_name, presence: true
validates :guardian_phone, presence: 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
guardian_address_street1 guardian_address_street2 guardian_address_city guardian_address_state guardian_address_zip guardian_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 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

@@ -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 medical misc)
AVAILABLE_RELEASE_TYPES = %w(appearance location material acquired_media talent music medical) AVAILABLE_RELEASE_TYPES = %w(appearance location material acquired_media talent music medical misc)
belongs_to :account belongs_to :account
has_many :acquired_media_releases, dependent: :destroy has_many :acquired_media_releases, dependent: :destroy
@@ -14,6 +14,7 @@ class Project < ApplicationRecord
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 :medical_releases, dependent: :destroy
has_many :misc_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 +24,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
@@ -35,6 +37,7 @@ class Project < ApplicationRecord
music_release: false, music_release: false,
talent_release: false, talent_release: false,
medical_release: false, medical_release: false,
misc_release: false,
video_analysis: false, video_analysis: false,
} }
end end
@@ -68,6 +71,7 @@ class Project < ApplicationRecord
music_release: true, music_release: true,
talent_release: true, talent_release: true,
medical_release: true, medical_release: true,
misc_release: true,
video_analysis: true, video_analysis: true,
} }
when "nat_geo" when "nat_geo"
@@ -80,6 +84,7 @@ class Project < ApplicationRecord
music_release: true, music_release: true,
talent_release: true, talent_release: true,
medical_release: true, medical_release: true,
misc_release: true,
video_analysis: true, video_analysis: true,
} }
else else

View File

@@ -24,7 +24,7 @@ class QrCode
end end
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 _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 medical misc)
def initialize(params) def initialize(params)
@params = params @params = params

View File

@@ -8,7 +8,12 @@ class SampleAppearanceRelease < AppearanceRelease
def default_attrs 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_first_name: "Some",
person_last_name: "Person", person_last_name: "Person",
person_phone: "555-555-5555", person_phone: "555-555-5555",

View File

@@ -11,7 +11,9 @@ class TalentRelease < ApplicationRecord
include Taggable include Taggable
include PersonName include PersonName
include GuardianPhotoable include GuardianPhotoable
include SecondGuardianPhotoable
include GuardianName include GuardianName
include SecondGuardianName
composed_of :person_address, composed_of :person_address,
class_name: "Address", class_name: "Address",
@@ -35,6 +37,17 @@ class TalentRelease < ApplicationRecord
%w(guardian_address_country country) %w(guardian_address_country country)
] ]
composed_of :guardian_2_address,
class_name: "Address",
mapping: [
%w(guardian_2_address_street1 street1),
%w(guardian_2_address_street2 street2),
%w(guardian_2_address_city city),
%w(guardian_2_address_state state),
%w(guardian_2_address_zip zip),
%w(guardian_2_address_country country)
]
def self.face_photo_acceptable_content_types def self.face_photo_acceptable_content_types
["image/png", "image/jpeg"] ["image/png", "image/jpeg"]
end end
@@ -58,6 +71,7 @@ class TalentRelease < 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, :guardian_2_email, email: true, allow_blank: true
validates :guardian_phone, presence: true validates :guardian_phone, presence: true
end end
@@ -84,6 +98,10 @@ class TalentRelease < ApplicationRecord
false false
end end
def second_guardian_present?
guardian_2_first_name.present?
end
def contract_file_name def contract_file_name
"#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime("%Y.%m.%d")}_#{release_number}_#{filename_suffix.parameterize}" "#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime("%Y.%m.%d")}_#{release_number}_#{filename_suffix.parameterize}"
end end

View File

@@ -0,0 +1,10 @@
class TaskRequest < ApplicationRecord
belongs_to :project
has_many_attached :files
enum status: [:pending, :completed, :cancelled]
scope :order_by_recent, -> { order(created_at: :desc) }
validates :time_allowed, numericality: { only_integer: true, greater_than_or_equal_to: 2 }
end

View File

@@ -12,7 +12,7 @@ class AcquiredMediaReleasePolicy < ApplicationPolicy
end end
def destroy? def destroy?
true user.manager? || user.account_manager?
end end
def tag_multiple? def tag_multiple?

View File

@@ -16,7 +16,7 @@ class AppearanceReleasePolicy < ReleasePolicy
end end
def destroy? def destroy?
true user.manager? || user.account_manager?
end end
def tag_multiple? def tag_multiple?

View File

@@ -1,5 +1,9 @@
class ContractPolicy < ApplicationPolicy class ContractPolicy < ApplicationPolicy
def show? def show?
user.manager? || user.account_manager? if record.respond_to?(:medical_release?) && record.medical_release?
user.account_manager?
else
user.manager? || user.account_manager?
end
end end
end end

View File

@@ -16,7 +16,7 @@ class LocationReleasePolicy < ReleasePolicy
end end
def destroy? def destroy?
true user.manager? || user.account_manager?
end end
def edit_photos? def edit_photos?

View File

@@ -16,7 +16,7 @@ class MaterialReleasePolicy < ReleasePolicy
end end
def destroy? def destroy?
true user.manager? || user.account_manager?
end end
def edit_photos? def edit_photos?

View File

@@ -12,7 +12,7 @@ class MedicalReleasePolicy < ReleasePolicy
end end
def destroy? def destroy?
true user.manager? || user.account_manager?
end end
def edit_photos? def edit_photos?
@@ -31,7 +31,11 @@ class MedicalReleasePolicy < ReleasePolicy
true true
end end
def download_single?
user.account_manager?
end
def download_multiple? def download_multiple?
true download_single?
end end
end end

View File

@@ -0,0 +1,41 @@
class MiscReleasePolicy < ReleasePolicy
def create?
true
end
def show?
true
end
def update?
!record.native?
end
def destroy?
user.manager? || user.account_manager?
end
def edit_photos?
true
end
def index?
true
end
def update_photos?
edit_photos?
end
def tag_multiple?
true
end
def download_single?
true
end
def download_multiple?
download_single?
end
end

View File

@@ -12,7 +12,7 @@ class MusicReleasePolicy < ReleasePolicy
end end
def destroy? def destroy?
true user.manager? || user.account_manager?
end end
def tag_multiple? def tag_multiple?

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

@@ -12,7 +12,7 @@ class TalentReleasePolicy < ReleasePolicy
end end
def destroy? def destroy?
true user.manager? || user.account_manager?
end end
def edit_photos? def edit_photos?

View File

@@ -0,0 +1,29 @@
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
def open_deliverable?
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

@@ -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 custom-select" %>
<%= 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,32 @@
<tr id="<%= dom_id(task_request) %>">
<td>
<%= task_request.id %>
</td>
<td>
<%= task_request.project.account.name %>
</td>
<td>
<%= task_request.project.name %>
</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,25 @@
<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>Account Name</th>
<th>Project Name</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="20" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>

View File

@@ -0,0 +1,49 @@
<div class="card shadow-sm">
<%= card_header text: "Task Details", close_action_path: [:admin, :task_requests] %>
<div class="card-body">
<div class="row">
<div class="col-md-6 col-sm-12">
<dl>
<%= description_list_pair_for @task_request.project.account, :name, custom_label: "Account Name", append: ":" %>
<%= description_list_pair_for @task_request.project, :name, custom_label: "Project Name", append: ":" %>
<%= description_list_pair_for @task_request, :created_at, append: ":" %>
<%= description_list_pair_for @task_request, :user_email, append: ":" %>
<%= description_list_pair_for @task_request, :status, append: ":" %>
</dl>
</div>
<div class="col-md-6 col-sm-12">
<dl>
<%= description_list_pair_for @task_request, :deadline, append: ":" %>
<%= description_list_pair_for @task_request, :time_allowed, append: ":" %>
<%= description_list_pair_for @task_request, :description, append: ":" %>
<%= description_list_pair_for @task_request, :additional_notes, append: ":" %>
</dl>
</div>
<div class="col-md-12">
<h2 class="h6 mt-3">Files:</h2>
<div class="pt-2 mx-n3">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th>Filename</th>
<th></th>
</tr>
</thead>
<tbody id="task_requests">
<% if @files.any? %>
<%= render partial: "task_requests/file", collection: @files %>
<% else %>
<tr>
<td colspan="12" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
<div class="mt-4" id="task_requests_pagiantion">
<%= will_paginate @files %>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -13,18 +13,29 @@
<div class="form-row"> <div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %> <%= 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.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>
<div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields"> <div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields">
<div class="form-row"> <%= card_field_set_tag t(".guardian_info.heading") do %>
<%= form.text_field :guardian_first_name, required: appearance_release.minor?, wrapper_class: "col-sm-3" %> <div class="form-row">
<%= form.text_field :guardian_last_name, required: appearance_release.minor?, wrapper_class: "col-sm-3" %> <%= form.text_field :guardian_first_name, required: appearance_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %> <%= form.text_field :guardian_last_name, required: appearance_release.minor?, wrapper_class: "col-sm-3" %>
</div> <%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %>
<div class="form-row"> <%= form.text_field :guardian_email, wrapper_class: "col-sm-6" %>
<%= form.text_field :guardian_address, wrapper_class: "col-sm-6" %> <%= form.text_field :guardian_address_street1, wrapper_class: "col-sm-6" %>
</div> </div>
<% end %>
<%= card_field_set_tag t(".guardian_2_info.heading") do %>
<div class="form-row">
<%= form.text_field :guardian_2_first_name, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_2_last_name, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_2_phone, wrapper_class: "col-sm-6" %>
<%= form.text_field :guardian_2_email, wrapper_class: "col-sm-6" %>
<%= form.text_field :guardian_2_address_street1, wrapper_class: "col-sm-6" %>
</div>
<% end %>
</div> </div>
<% end %> <% end %>
@@ -59,20 +70,36 @@
<div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields"> <div class="<%= class_string("collapse" => !appearance_release.minor?) %>" data-ujs-target="guardian-fields">
<div class="text-left"> <div class="text-left">
<p><%= t(".photos.guardian_photo.heading") %></p> <p><%= t(".photos.guardian_photo.heading") %></p>
<div class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-photo-input]"> <div id='guardian-photo-preview' class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-photo-input]">
<div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center"> <div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center">
<span>No photo yet</span> <span>No photo yet</span>
</div> </div>
</div> </div>
<% if appearance_release.guardian_photo.attached? %> <% if appearance_release.guardian_photo.attached? %>
<%= javascript_tag nonce: true do %> <%= javascript_tag nonce: true do %>
App.PhotoPreview.set("[data-behavior=guardian-photo-preview]", "<%= url_for(appearance_release.guardian_photo.variant(auto_orient: true, resize: '200x200')) %>"); App.PhotoPreview.set("#guardian-photo-preview", "<%= url_for(appearance_release.guardian_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %> <% end %>
<% end %> <% end %>
<div class="d-inline-block"> <div class="d-inline-block">
<%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if appearance_release.guardian_photo.attached?%> <%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if appearance_release.guardian_photo.attached?%>
<%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, help: "PNG or JPG only", accept: appearance_release.class.face_photo_acceptable_content_types.join(",") %> <%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, help: "PNG or JPG only", accept: appearance_release.class.face_photo_acceptable_content_types.join(",") %>
</div> </div>
<p><%= t(".photos.guardian_2_photo.heading") %></p>
<div id='guardian-2-photo-preview' class="d-inline-block mb-2" data-behavior="guardian-photo-preview" data-file-input="[data-ujs-target=guardian-2-photo-input]">
<div class="align-items-center d-flex photo-preview img-thumbnail justify-content-center">
<span>No photo yet</span>
</div>
</div>
<% if appearance_release.guardian_2_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("#guardian-2-photo-preview", "<%= url_for(appearance_release.guardian_2_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %>
<% end %>
<div class="d-inline-block">
<%= form.hidden_field :guardian_2_photo, value: form.object.guardian_2_photo.signed_id if appearance_release.guardian_2_photo.attached?%>
<%= form.file_field :guardian_2_photo, hide_label: true, data: { ujs_target: "guardian-2-photo-input" }, help: "PNG or JPG only", accept: appearance_release.class.face_photo_acceptable_content_types.join(",") %>
</div>
</div> </div>
</div> </div>
<% end %> <% end %>

View File

@@ -11,6 +11,14 @@
<hr class="divider-light mx-n4"> <hr class="divider-light mx-n4">
<nav> <nav>
<ul class="nav nav-pills nav-pills-dark flex-column"> <ul class="nav nav-pills nav-pills-dark flex-column">
<% if Current.account.taskme_enabled? %>
<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, :taskme) %>
<%= product_wordmark :task_me, class: class_string("d-inline-block", "disabled" => !Current.account.taskme_enabled?) %>
<% end %>
</li>
<% end %>
<li class="nav-item"> <li class="nav-item">
<%= link_to [project, :contract_templates], class: class_string("nav-link", "active" => %w(contract_templates release_template_imports).include?(controller_name)) do %> <%= link_to [project, :contract_templates], class: class_string("nav-link", "active" => %w(contract_templates release_template_imports).include?(controller_name)) do %>
<%= lock_icon_for Current.account, :releaseme %> <%= lock_icon_for Current.account, :releaseme %>

View File

@@ -2,6 +2,10 @@
<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 %>
@@ -11,17 +15,9 @@
<% end %> <% end %>
</td> </td>
<td> <td>
<img src="<%= qr_codes[copy_index] %>" /> <img class="qr-code" 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 @@
<%= 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, wrapper_class: "w-65 mr-2", id: "broadcast_files_#{token}" %> <%= 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.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

@@ -3,12 +3,12 @@
<meta name="project-id" content="<%= @project.id %>"> <meta name="project-id" content="<%= @project.id %>">
<% end %> <% end %>
<% if @broadcast %> <% if @broadcast %>
<meta name="broadcast-token" content="<%= @broadcast.token %>"> <meta name="broadcast-token" current="true" content="<%= @broadcast.token %>">
<% end %> <% end %>
<% # Subscribe to Action Cable for every broadcast including those in multi-view %> <% # Subscribe to Action Cable for every broadcast including those in multi-view %>
<% @multi_view_broadcasts.each do |multi_view_broadcast| %> <% @multi_view_broadcasts.each do |multi_view_broadcast| %>
<% if multi_view_broadcast.token != @broadcast.token %> <% 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 %> <% end %>
<% end %> <% end %>
@@ -33,7 +33,7 @@
<%= link_to "Switch View", "#", class: "btn btn-light border dropdown-toggle", role: "button", id: "dropdownMenuLink", data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } %> <%= link_to "Switch View", "#", class: "btn btn-light border dropdown-toggle", role: "button", id: "dropdownMenuLink", data: { toggle: "dropdown" }, aria: { haspopup: "true", expanded: "false" } %>
<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> <%= link_to fa_icon("check", text: @broadcast.name.titleize), "#", class: "dropdown-item active" %>
<% @multi_view_broadcasts.each do |broadcast| %> <% @multi_view_broadcasts.each do |broadcast| %>
<% if broadcast.id != @broadcast.id %> <% if broadcast.id != @broadcast.id %>
<%= link_to broadcast.name.titleize, broadcast.url, class: class_string("dropdown-item", "active" => @broadcast.id == broadcast.id) %> <%= link_to broadcast.name.titleize, broadcast.url, class: class_string("dropdown-item", "active" => @broadcast.id == broadcast.id) %>
@@ -159,4 +159,4 @@
</div> </div>
</div> </div>
</div> </div>
<div> </div>

View File

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

View File

@@ -2,21 +2,20 @@
<%= 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: "#guardian_clause", show_values: %w(appearance talent) }, 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_show_values_mapping: { "#guardian_clause": %w(appearance talent misc medical), "#fee_field": %w(appearance talent location material acquired_media), "#exploitable_rights_fields": %w(appearance talent location material acquired_media), "#custom_fields": %w(medical misc) } }, class: "form-control custom-select" %>
</div> </div>
<div class="form-row"> <div class="form-row" id="fee_field">
<%= 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: "$", 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")do %> <%= field_set_tag content_tag(:span, t(".exploitable_rights.heading"), class: "h6 text-muted text-uppercase"), id: "exploitable_rights_fields" 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 %>
@@ -28,6 +27,12 @@
</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

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

View File

@@ -5,6 +5,9 @@
<% if release.respond_to? :guardian_photo %> <% if release.respond_to? :guardian_photo %>
<% @total_photos_count += release.guardian_photo.attached? ? 1 : 0 %> <% @total_photos_count += release.guardian_photo.attached? ? 1 : 0 %>
<% end %> <% end %>
<% if release.respond_to? :guardian_2_photo %>
<% @total_photos_count += release.guardian_2_photo.attached? ? 1 : 0 %>
<% end %>
<p class="heading"><strong><u><%= t '.heading', count: @total_photos_count %></u></strong></p> <p class="heading"><strong><u><%= t '.heading', count: @total_photos_count %></u></strong></p>
<ul> <ul>
@@ -29,6 +32,14 @@
<%= release.guardian_photo.filename.to_s %> <%= release.guardian_photo.filename.to_s %>
</li> </li>
<% end %> <% end %>
<% if release.respond_to?(:guardian_2_photo) && release.guardian_2_photo.attached? %>
<br>
<p class="heading"><strong><%= t '.guardian_2_photo_heading' %></strong></p>
<li>
<%= image_tag release.guardian_2_photo.variant(auto_orient: true, resize: "200x200") %><br />
<%= release.guardian_2_photo.filename.to_s %>
</li>
<% end %>
<% end %> <% end %>
</ul> </ul>

View File

@@ -0,0 +1,8 @@
<p class="heading"><strong><u><%= t ".heading.#{releasable.model_name.param_key}" %></u></strong></p>
<% (1..releasable.class::NUMBER_OF_CUSTOM_FIELDS).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 %>

View File

@@ -56,7 +56,23 @@
<%= 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>
<% if releasable.respond_to?(:second_guardian_present?) && releasable.second_guardian_present? %>
<br/>
<p class="text-left"><strong>Second guardian Information</strong></p>
<% # Second guardian information %>
<dl>
<%= description_list_pair_for releasable, :guardian_2_name, append: ":" %>
<%= description_list_pair_for releasable, :guardian_2_address, append: ":" %>
<%= description_list_pair_for releasable, :guardian_2_phone, append: ":" %>
<%= description_list_pair_for releasable, :guardian_2_email, append: ":" %>
</dl>
<% end %>
<% end %> <% end %>

View File

@@ -15,6 +15,13 @@
<p class="text-left"><strong>Guardian Clause</strong></p> <p class="text-left"><strong>Guardian Clause</strong></p>
<%= contract_template.guardian_clause %> <%= contract_template.guardian_clause %>
<% end %> <% end %>
<% if releasable.model_name.in? %w(MedicalRelease MiscRelease) %>
<div class="page">
<%= render "contracts/questionnaire", releasable: releasable, contract_template: contract_template, preview: preview %>
</div>
<% end %>
<div class="page"> <div class="page">
<%= render "contracts/signature_page", releasable: releasable, contract_template: contract_template, preview: preview %> <%= render "contracts/signature_page", releasable: releasable, contract_template: contract_template, preview: preview %>
</div> </div>

View File

@@ -37,7 +37,7 @@
<% if policy(medical_release.tags).new? %> <% 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 %> <%= link_to fa_icon("tags fw", text: "Tags"), [:new, medical_release, :acts_as_taggable_on_tag], class: "dropdown-item", remote: true %>
<% end %> <% end %>
<% if policy(Contract).show? && (medical_release.contract.attached? || medical_release.contract_template.present?) %> <% if policy(MedicalRelease).download_single? && 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" %> <%= link_to fa_icon("download fw", text: "Download"), [medical_release, :contracts, format: "pdf"], class: "dropdown-item", target: "_blank" %>
<% end %> <% end %>
<% if policy(medical_release).destroy? %> <% if policy(medical_release).destroy? %>

View File

@@ -0,0 +1,48 @@
<tr id="<%= dom_id(misc_release) %>">
<td data-behavior="select"><%= check_box_tag "misc_release_ids[]", misc_release.id, false %></td>
<td>
<% if misc_release.photo.attached? %>
<%= image_tag medium_variant(misc_release.photo), class: "img-fluid" %>
<% end %>
</td>
<td>
<%= misc_release.name %>
</td>
<td>
<%= contact_info(
address: misc_release.person_address,
phone: misc_release.person_phone,
email: misc_release.person_email
) %>
</td>
<td>
<%= notes_preview misc_release.notes.order_by_recent %>
</td>
<td id="<%= dom_id misc_release, "tags_preview" %>">
<%= tags_preview misc_release, misc_release.tags %>
</td>
<td>
<%= misc_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, misc_release, :note], class: "dropdown-item", remote: true %>
<% end %>
<% if policy(misc_release.tags).new? %>
<%= link_to fa_icon("tags fw", text: "Tags"), [:new, misc_release, :acts_as_taggable_on_tag], class: "dropdown-item", remote: true %>
<% end %>
<% if policy(MedicalRelease).download_single? && policy(Contract).show? && (misc_release.contract.attached? || misc_release.contract_template.present?) %>
<%= link_to fa_icon("download fw", text: "Download"), [misc_release, :contracts, format: "pdf"], class: "dropdown-item", target: "_blank" %>
<% end %>
<% if policy(misc_release).destroy? %>
<%= link_to fa_icon("trash fw", text: "Delete"), misc_release, class: "dropdown-item", method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
</div>
</div>
</td>
</tr>

View File

@@ -0,0 +1,48 @@
<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 @misc_releases.any? && policy(MiscRelease).tag_multiple? %>
<%= button_to_bulk_tagging(@project) %>
<% end %>
<% if @misc_releases.any? && policy(MiscRelease).download_multiple? %>
<%= link_to "Download All", [@project, :contract_downloads, release_type: @misc_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, :misc_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 "misc_release_ids[]", false, false %></th>
<th></th>
<th><%= MiscRelease.human_attribute_name(:person_name) %></th>
<th><%= MiscRelease.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="misc_releases">
<% if @misc_releases.any? %>
<%= render @misc_releases %>
<% else %>
<tr>
<td colspan="12" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="misc_releases_pagination" class="mt-3">
<%= will_paginate @misc_releases %>
</div>

View File

@@ -0,0 +1,3 @@
$("#misc_releases").html("<%= j render(@misc_releases) %>");
$("form input[type='search']").val("<%= params[:query] %>");
$("#misc_releases_pagination").html("<%= j will_paginate(@misc_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: "#other_client", show_values: [: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_show_values_mapping: { "#other_client": [: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 %>

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