Compare commits

...

4 Commits

Author SHA1 Message Date
Bilal
d11ceab916 update struct 2020-07-01 08:57:19 +02:00
Bilal
e1c003d6af fix MR comments 2020-07-01 08:56:23 +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
78 changed files with 2347 additions and 259 deletions

View File

@@ -4,7 +4,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "2.6.3"
# 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
gem "pg", "~> 0.18"
# Use Puma as the app server
@@ -30,9 +30,9 @@ gem "active_storage_base64", "~> 1.0.0"
gem "image_processing", "~> 1.2"
# 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
gem "aws-sigv4", "~> 1.0.2"
gem "aws-sigv4", "~> 1.1"
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", ">= 1.1.0", require: false

View File

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

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

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

View File

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

View File

@@ -17,7 +17,7 @@ class AccountsController < ApplicationController
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)
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
else
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

@@ -19,5 +19,11 @@ class Api::AppearanceReleasesController < Api::ReleasesController
guardian_photo[:io] = StringIO.new(Base64.decode64(guardian_photo[:io]))
release.guardian_photo.attach(io: guardian_photo[:io], filename: guardian_photo[:filename])
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

View File

@@ -103,10 +103,16 @@ class Api::ReleasesController < Api::ApiController
if ["appearance_release", "talent_release"].include?(name)
has_many :guardian_photos do
data do
[@object.guardian_photo.try(:attachment)].compact
[
@object.guardian_photo.try(:attachment),
@object.guardian_2_photo.try(:attachment)
].compact
end
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
@@ -170,7 +176,7 @@ class Api::ReleasesController < Api::ApiController
def release_create_params
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 = parameters.slice(*keys).except(:created_at, :updated_at, :id, :user_id, :signature)
parameters

View File

@@ -17,5 +17,11 @@ class Api::TalentReleasesController < Api::ReleasesController
guardian_photo[:io] = StringIO.new(Base64.decode64(guardian_photo[:io]))
release.guardian_photo.attach(io: guardian_photo[:io], filename: guardian_photo[:filename])
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

View File

@@ -45,42 +45,59 @@ class Public::TalentReleasesController < Public::BaseController
.permit(
person_params,
guardian_params,
second_guardian_params,
:signature_base64,
:locale,
:contract_template,
photos: [],
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,
%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
[
: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,
%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

View File

@@ -60,9 +60,14 @@ class StreamNotificationsController < ApplicationController
def set_broadcast
if notification_type == "video.asset.static_renditions.ready"
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
@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

View File

@@ -61,15 +61,67 @@ class TalentReleasesController < ApplicationController
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
params.require(:talent_release).permit(
:person_first_name, :person_last_name, :person_phone, :guardian_photo, :person_email,
:person_address_street1, :person_address_street2, :person_address_city, :person_address_state, :person_address_zip, :person_address_country,
: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,
:contract, { photos: [] },
:applicable_medium_id, :applicable_medium_text, :territory_id, :territory_text, :term_id, :term_text, :restriction_id, :restriction_text
)
params.require(:talent_release).permit(person_params,
guardian_params,
second_guardian_params,
:contract, { photos: [] },
:applicable_medium_id,
:applicable_medium_text,
:territory_id,
:territory_text,
:term_id,
:term_text,
:restriction_id,
:restriction_text)
end
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

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

View File

@@ -11,6 +11,8 @@ module DropzoneHelper
t 'location_releases.form.photos.dropzone_label'
when "directory"
"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
"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

View File

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

View File

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

View File

@@ -1,12 +1,14 @@
class SubmitHubspotFormJob < ApplicationJob
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"]
return unless hubspot_form_guid.present?
submission_params = {
email: email,
first_name: first_name,
last_name: last_name,
email: email,
company: company_name
}.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,6 +54,7 @@ class Account < ApplicationRecord
Download.where(project: projects),
User.joins(:project_memberships).where(project_memberships: { project: projects }),
Broadcast.where(project: projects),
TaskRequest.where(project: projects),
ZoomMeeting.where(project: projects),
MedicalRelease.where(project: projects),
MiscRelease.where(project: projects),
@@ -82,6 +83,10 @@ class Account < ApplicationRecord
plan_uid.to_s == "me_suite" || plan_uid.to_s == "releaseme"
end
def taskme_enabled?
plan_uid.to_s == "me_suite" || plan_uid.to_s == "taskme"
end
def plan_name
case plan_uid.to_s
when "deliverme"
@@ -90,6 +95,8 @@ class Account < ApplicationRecord
"DirectME"
when "releaseme"
"ReleaseME"
when "taskme"
"TaskME"
when "me_suite"
"ME Suite"
end

View File

@@ -24,6 +24,7 @@ class Project < ApplicationRecord
has_many :downloads, dependent: :destroy
has_many :broadcasts, dependent: :destroy
has_many :zoom_meetings, dependent: :destroy
has_many :task_requests, dependent: :destroy
accepts_nested_attributes_for :project_memberships

View File

@@ -11,7 +11,9 @@ class TalentRelease < ApplicationRecord
include Taggable
include PersonName
include GuardianPhotoable
include SecondGuardianPhotoable
include GuardianName
include SecondGuardianName
composed_of :person_address,
class_name: "Address",
@@ -35,6 +37,17 @@ class TalentRelease < ApplicationRecord
%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
["image/png", "image/jpeg"]
end
@@ -58,6 +71,7 @@ class TalentRelease < ApplicationRecord
# These validations apply to releases being signed by a minor
with_options if: :minor? do
validates :guardian_first_name, :guardian_last_name, presence: true
validates :guardian_email, :guardian_2_email, email: true, allow_blank: true
validates :guardian_phone, presence: true
end
@@ -84,6 +98,10 @@ class TalentRelease < ApplicationRecord
false
end
def second_guardian_present?
guardian_2_first_name.present?
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

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

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

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

View File

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

@@ -11,6 +11,12 @@
<hr class="divider-light mx-n4">
<nav>
<ul class="nav nav-pills nav-pills-dark flex-column">
<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>
<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 %>
<%= lock_icon_for Current.account, :releaseme %>

View File

@@ -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" } %>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<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| %>
<% if 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>

View File

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

View File

@@ -31,8 +31,6 @@
<%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>
@@ -51,8 +49,6 @@
<%= form.text_field :guardian_first_name, required: @talent_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_last_name, required: @talent_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :guardian_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian" %>
@@ -87,6 +83,48 @@
</div>
<% end %>
<hr>
<%= 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" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian_2" %>
<% end %>
<hr>
<%= card_field_set_tag t(".guardian_2_photo.heading") do %>
<div class="alert alert-warning font-weight-bold"><%= t ".guardian_2_photo.instructions" %></div>
<div class="text-center">
<div 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><%= t ".guardian_2_photo.no_photo" %></span>
</div>
</div>
<div class="d-inline-block text-left">
<% if @talent_release.guardian_2_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("[data-behavior=guardian-photo-preview]", "<%= url_for(@talent_release.guardian_2_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %>
<% end %>
<div class="hidden-file-input">
<%= form.hidden_field :guardian_2_photo, value: form.object.guardian_2_photo.signed_id if @talent_release.guardian_2_photo.attached? %>
<%= form.file_field :guardian_2_photo, hide_label: true, data: { ujs_target: "guardian-2-photo-input" }, accept: @talent_release.class.face_photo_acceptable_content_types.join(","), direct_upload: true %>
</div>
<%= button_tag t(".guardian_2_photo.take_photo"), type: "button", class: "btn btn-lg btn-primary take-photo-button", data: { behavior: "trigger-click", target: "[data-ujs-target=guardian-2-photo-input]" } %>
</div>
<p class="p-2 font-weight-bold">
<%= fa_icon "arrow-up", text: t(".guardian_2_photo.camera_instructions_html") %><br>
<small class="text-muted"><%= t ".guardian_2_photo.warning" %></small>
</p>
</div>
<% end %>
<hr>
</div>
<hr>

View File

@@ -9,22 +9,30 @@
<%= form.text_field :person_first_name, required: true, wrapper_class: "col-sm-3" %>
<%= form.text_field :person_last_name, required: true, wrapper_class: "col-sm-3" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "person" %>
<div class="<%= class_string("collapse" => !talent_release.minor?) %>" data-ujs-target="guardian-fields">
<div class="form-row">
<%= form.text_field :guardian_first_name, required: talent_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_last_name, required: talent_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :guardian_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian" %>
<%= card_field_set_tag t(".guardian_info.heading") do %>
<div class="form-row">
<%= form.text_field :guardian_first_name, required: talent_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_last_name, required: talent_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.phone_field :guardian_phone, wrapper_class: "col-sm-6" %>
<%= form.text_field :guardian_email, wrapper_class: "col-sm-6" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian" %>
<% end %>
<%= card_field_set_tag t(".guardian_2_info.heading") do %>
<div class="form-row">
<%= form.text_field :guardian_2_first_name, required: talent_release.minor?, wrapper_class: "col-sm-3" %>
<%= form.text_field :guardian_2_last_name, required: talent_release.minor?, 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" %>
</div>
<%= render "shared/address_fields", form: form, subject: "guardian_2" %>
<% end %>
</div>
<% end %>
@@ -44,20 +52,36 @@
<br>
<div class="text-left">
<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">
<span>No photo yet</span>
</div>
</div>
<% if talent_release.guardian_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("[data-behavior=guardian-photo-preview]", "<%= url_for(talent_release.guardian_photo.variant(auto_orient: true, resize: '200x200')) %>");
App.PhotoPreview.set("#guardian-photo-preview", "<%= url_for(talent_release.guardian_photo.variant(auto_orient: true, resize: '200x200')) %>");
<% end %>
<% end %>
<div class="d-inline-block">
<%= form.hidden_field :guardian_photo, value: form.object.guardian_photo.signed_id if talent_release.guardian_photo.attached?%>
<%= form.file_field :guardian_photo, hide_label: true, data: { ujs_target: "guardian-photo-input" }, help: "PNG or JPG only", accept: talent_release.class.face_photo_acceptable_content_types.join(",") %>
</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 talent_release.guardian_2_photo.attached? %>
<%= javascript_tag nonce: true do %>
App.PhotoPreview.set("#guardian-2-photo-preview", "<%= url_for(talent_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 talent_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: talent_release.class.face_photo_acceptable_content_types.join(",") %>
</div>
</div>
<hr>
</div>

View File

@@ -0,0 +1,6 @@
<tr>
<td><%= file.filename %></td>
<td class="text-right">
<%= link_to fa_icon("download"), file, target: "_blank" %>
</td>
</tr>

View File

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

View File

@@ -0,0 +1,45 @@
<tr>
<td>
<%= task_request.created_at.strftime('%D') %>
</td>
<td>
<%= task_request.deadline.try(:strftime, '%D') %>
</td>
<td>
<%= truncate(task_request.description) {
link_to t('.actions.read_more'),
'#',
class: 'alert-link',
data: {
toggle: "popover",
content: task_request.description,
trigger: "hover"
}
} %>
</td>
<td>
<%= task_request.time_allowed %>
</td>
<td>
<%= task_request.status.titleize %>
</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(task_request).show? %>
<%= link_to fa_icon("tasks fw", text: "View"), [task_request.project, task_request], class: "dropdown-item", target: '_blank' %>
<% end %>
<% if policy(task_request).edit? %>
<%= link_to fa_icon("pencil fw", text: "Edit"), [:edit, task_request.project, task_request], class: "dropdown-item" %>
<% end %>
<% if policy(task_request).open_deliverable? && task_request.status == "completed" %>
<%= link_to fa_icon("external-link fw", text: t(".actions.open_deliverable")), task_request.deliverable_url, class: "dropdown-item", target: '_blank' %>
<% end %>
<% if policy(task_request).cancel? && !task_request.cancelled? %>
<%= link_to fa_icon("ban fw", text: "Cancel"), [:cancel, task_request.project, task_request], class: "dropdown-item", method: :post %>
<% end %>
</div>
</div>
</td>
</tr>

View File

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

View File

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

View File

@@ -0,0 +1,39 @@
<%= product_wordmark :task_me, class: "small mb-3" %>
<div class="row">
<div class="col-md-12">
<div class="d-md-flex d-sm-flex flex-sm-column flex-md-row flex-md-wrap mb-3">
<% if policy(TaskRequest).new? %>
<%= link_to fa_icon("plus", text: t(".actions.new")), [:new, @project, :task_request], class: "btn btn-primary mb-2" %>
<% end %>
</div>
</div>
</div>
<div class="border bg-white rounded shadow-sm pb-3 table-responsive">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th><%= t(".table_headers.task_request_created_on") %></th>
<th><%= t(".table_headers.task_request_deadline") %></th>
<th><%= t(".table_headers.task_request_description") %></th>
<th><%= t(".table_headers.task_request_time_allowed") %></th>
<th><%= t(".table_headers.task_request_status") %></th>
<th></th>
</tr>
</thead>
<tbody id="task_requests">
<% 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>
<div id="task_requests_pagination" class="mt-3">
<%= will_paginate @task_requests %>
</div>

View File

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

View File

@@ -0,0 +1,46 @@
<div class="card shadow-sm">
<%= card_header text: "Task Details", close_action_path: [@project, :task_requests] %>
<div class="card-body">
<div class="row">
<div class="col-md-6 col-sm-12">
<dl>
<%= description_list_pair_for @task_request, :description, append: ":" %>
<%= description_list_pair_for @task_request, :created_at, 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, :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: "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

@@ -0,0 +1,58 @@
<div class="d-flex flex-row">
<div class="d-flex flex-column">
<%= product_wordmark :task_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(TaskRequest).new? %>
<%= link_to t(".actions.create_task_request"), [:new, @project, :task_request], 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.enter_task_request' %></li>
<li><%= t '.list_items.state_deadline' %></li>
<li><%= t '.list_items.enter_number_of_hours' %></li>
<li><%= t '.list_items.virtual_assistant_delivers_task' %></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.reduces_need_for_full_time_staff'))) %>
<%= content_tag(:li, fa_icon("check li", text: t('.list_items.reduces_workload'))) %>
<%= content_tag(:li, fa_icon("check li", text: t('.list_items.spend_per_task'))) %>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,17 @@
<tr>
<td>
<%= task.created_at.strftime('%D') %>
</td>
<td>
<%= task.deadline.try(:strftime, '%D') %>
</td>
<td>
<%= task.time_allowed %>
</td>
<td>
<%= task.status.titleize %>
</td>
<td>
<%= link_to "View Deliverable", task.deliverable_url, target: "_blank" %>
</td>
</tr>

View File

@@ -0,0 +1,26 @@
<div class="border bg-white rounded shadow-sm pb-3 table-responsive">
<table class="table table-striped tr-px-4 align-all-middle">
<thead class="thead-light">
<tr>
<th><%= t(".table_headers.task_request_created_on") %></th>
<th><%= t(".table_headers.task_request_deadline") %></th>
<th><%= t(".table_headers.task_request_time_allowed") %></th>
<th><%= t(".table_headers.task_request_status") %></th>
<th><%= t(".table_headers.task_request_results") %></th>
</tr>
</thead>
<tbody id="task_requests">
<% if @tasks.any? %>
<%= render partial: "task", collection: @tasks %>
<% else %>
<tr>
<td colspan="5" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="task_requests_pagination" class="mt-3">
<%= will_paginate @tasks %>
</div>

View File

@@ -97,6 +97,13 @@ en:
application:
header:
sign_out: Sign Out
task_requests:
index:
empty: Task requests will appear here
show:
empty: Attached files will appear here.
update:
notice: The task request has been updated successfully
users:
create:
notice: The user was created
@@ -320,6 +327,8 @@ en:
contract_template:
fee: Leave at $0.00 for no-fee
guardian_clause: Leave blank if not required for this contract
task_request:
time_allowed: Minimum of 2 hours, no partial hours allowed
video:
audio_only_edl_file: If you do not upload an Audio Only EDL, the software will not generate a BiG Music Cue Sheet.
edl_file: Please follow our directions on exporting the All Tracks EDL. Failure to do so could result in inaccurate and incomplete reporting.
@@ -458,6 +467,16 @@ en:
project:
predefined_client_name: Client
talent_release:
guardian_2_address_city: Guardian 2 city
guardian_2_address_country: Guardian 2 country
guardian_2_address_state: Guardian 2 state
guardian_2_address_street1: Guardian 2 address
guardian_2_address_street2: Guardian 2 address (Line 2)
guardian_2_address_zip: Guardian 2 zip code
guardian_2_email: Guardian 2 email
guardian_2_first_name: Guardian 2 first name
guardian_2_last_name: Guardian 2 last name
guardian_2_phone: Guardian 2 phone
guardian_address_city: City
guardian_address_country: Guardian country
guardian_address_state: State
@@ -857,6 +876,7 @@ en:
music_release: Music Releases (%{count})
report: Reports
talent_release: Talent Releases (%{count})
tasks: Tasks
public:
acquired_media_releases:
new:
@@ -1011,6 +1031,16 @@ en:
notice: Your release has been signed. Thank you!
new:
cancel: Cancel
guardian_2_info:
heading: Second Guardian Information (if company requires)
guardian_2_photo:
camera_instructions_html: Click <em>Take Photo</em> to Turn ON Camera
heading: Second Guardian Photo
instructions: >
Lastly, it's time for second guardian to take a selfie photo! Please remove your hat and sunglasses (regular eyewear is ok), make sure that you are the only person in the photo, look straight into the camera, and say Cheese!
no_photo: No photo yet
take_photo: Take Photo
warning: If your photo appears sideways, it will be autocorrected when you submit your release.
guardian_clause:
heading: Guardian Clause
guardian_info:
@@ -1098,6 +1128,7 @@ en:
tag_multiple_releases: Add Tag
tag_multiple_releases_form:
submit: Add
task_me: Task
tags:
form:
submit: Add
@@ -1111,7 +1142,13 @@ en:
form:
contract_and_rights:
heading: 2 of 3 Contract & Exploitable Rights
guardian_2_info:
heading: Guardian Information (if company requires)
guardian_info:
heading: Guardian Information
photos:
guardian_2_photo:
heading: Second Guardian Photo
guardian_photo:
heading: Guardian Photo
heading: 3 of 3 Photos
@@ -1133,6 +1170,71 @@ en:
manage: Manage
update:
notice: The talent release has been updated
task_requests:
cancel:
notice: Task has been cancelled successfully.
create:
notice: Task request created succussfully.
success_message: Your task request was successfully submitted. Thank you. A chat window will pop up on the lower right in a few seconds.
edit:
heading:
Edit Task Request
form:
info_message: After submitting this task request, you'll be connected via chat with a ME Suite representative.
labels:
additional_notes: Please add any additional notes we should be aware of regarding this task.
deadline: What is the deadline for this task?
description: Please describe the task.
files: Please attach any files related to this task
time_allowed: How many hours would you like a TaskME representative to work on this task?
index:
actions:
new: Create Task Request
empty: Task requests will appear here.
table_headers:
task_request_created_on: Created On
task_request_deadline: Deadline
task_request_description: Description
task_request_results: Task Results
task_request_status: Status
task_request_time_allowed: Time Allowed
new:
heading: New Task Request
show:
empty: Attached files will appear here.
splash:
actions:
book_demo: Schedule a Demo
create_task_request: Create Task Request
headings:
benefits: Benefits
how_it_works: How It Works
subtitle: Pay-by-the-hour, digitally-enabled remote assistants
welcome: Welcome to
list_items:
enter_number_of_hours: Enter the number of hours you want the task worked on
enter_task_request: Enter your task request
reduces_need_for_full_time_staff: Reduces need to hire full-time staff
reduces_workload: Reduces workload for current staff
spend_per_task: Spend as little as $60 per task
state_deadline: State your deadline
virtual_assistant_delivers_task: Virtual assistant delivers task via TaskME portal
task_request:
actions:
manage: Manage
open_deliverable: Open Deliverable
read_more: read more
update:
notice: Task request updated successfully.
tasks:
index:
empty: Tasks will appear here.
table_headers:
task_request_created_on: Created On
task_request_deadline: Deadline
task_request_results: Task Results
task_request_status: Status
task_request_time_allowed: Time Allowed
user_mailer:
existing_account:
subject: You've been added as a ME Suite Account Manager

View File

@@ -194,6 +194,36 @@ es:
name: Nómbre del proyecto de vídeo
producer_address: Dirección del productor
producer_name: Nómbre del productor
talen_release:
guardian_2_address_city: Guardian 2 city (ES)
guardian_2_address_country: Guardian 2 country (ES)
guardian_2_address_state: Guardian 2 state (ES)
guardian_2_address_street1: Guardian 2 address (ES)
guardian_2_address_street2: Guardian 2 address (Line 2) (ES)
guardian_2_address_zip: Guardian 2 zip code (ES)
guardian_2_email: Guardian 2 email (ES)
guardian_2_first_name: Guardian 2 first name (ES)
guardian_2_last_name: Guardian 2 last name (ES)
guardian_2_phone: Guardian 2 phone (ES)
guardian_address_city: City (ES)
guardian_address_country: Guardian country (ES)
guardian_address_state: State (ES)
guardian_address_street1: Guardian address (ES)
guardian_address_street2: Guardian address (Line 2) (ES)
guardian_address_zip: Zip code (ES)
guardian_email: Guardian email address (ES)
guardian_name: Guardian name (ES)
guardian_phone: Guardian phone number (ES)
minor: Is the person a minor? (ES)
person_address_city: City (ES)
person_address_country: Country (ES)
person_address_state: State (ES)
person_address_street1: Address (ES)
person_address_street2: Address (Line 2) (ES)
person_address_zip: Zip code (ES)
person_email: Email address (ES)
person_name: Name (ES)
person_phone: Phone number (ES)
placeholder:
appearance_release:
person_address: Calle, Número de apartamento, Ciudad, Estado, Código Postal
@@ -281,8 +311,19 @@ es:
warning: Si su foto aparece de lado, se corregirá automáticamente cuando actualizar la autorización
talent_releases:
new:
guardian_2_info:
heading: Second Guardian Information (if company requires) (ES)
guardian_2_photo:
camera_instructions_html: ""
heading: Second Guardian Photo (ES)
instructions: ""
no_photo: ""
take_photo: ""
warning: ""
guardian_clause:
heading: Guardian Clause (ES)
guardian_info:
heading: ""
guardian_photo:
camera_instructions_html: (ES) Click <em>Take Photo</em> to Turn ON Camera (ES)
heading: Guardian Photo (ES)
@@ -290,6 +331,8 @@ es:
no_photo: No hay foto todavía
take_photo: Take Photo (ES)
warning: (ES) If your photo appears sideways, it will be autocorrected when you submit your release. (ES)
photo:
heading: Photos (ES)
teams:
show:
choose_project: ¿Qué proyecto de la lista de abajo asistirá?
@@ -298,6 +341,42 @@ es:
print: Print (ES)
talent_releases:
form:
guardian_2_info:
heading: Guardian Information (if company requires) (ES)
guardian_info:
heading: Guardian Information (ES)
photos:
guardian_2_photo:
heading: Second Guardian Photo (ES)
guardian_photo:
heading: Guardian Photo (ES)
task_requests:
create:
success_message: Your task request was successfully submitted. Thank you. A chat window will pop up on the lower right in a few seconds. (ES)
form:
info_message: After submitting this task request, you'll be connected via chat with a ME Suite representative. (ES)
index:
table_headers:
task_request_description: Description (ES)
splash:
actions:
book_demo: Schedule a Demo (ES)
create_task_request: Create Task Request
headings:
benefits: Benefits (ES)
how_it_works: How It Works (ES)
subtitle: Pay-by-the-hour, digitally-enabled remote assistants (ES)
welcome: Welcome to (ES)
list_items:
enter_number_of_hours: Enter the number of hours you want the task worked on (ES)
enter_task_request: Enter your task request (ES)
reduces_need_for_full_time_staff: Reduces need to hire full-time staff (ES)
reduces_workload: Reduces workload for current staff (ES)
spend_per_task: Spend as little as $60 per task (ES)
state_deadline: State your deadline (ES)
virtual_assistant_delivers_task: Virtual assistant delivers task via TaskME portal (ES)
task_request:
actions:
manage: Manage (ES)
open_deliverable: Open Deliverable (ES)
read_more: read more (ES)

View File

@@ -31,6 +31,7 @@ Rails.application.routes.draw do
resources :users, only: [:index, :new, :create, :edit, :update, :destroy] do
resource :masquerade, only: :create
end
resources :task_requests, only: [:index, :edit, :update, :show]
root to: "accounts#index", as: :signed_in_root
end
@@ -99,6 +100,12 @@ Rails.application.routes.draw do
delete :destroy_file
end
end
resources :task_requests, except: :destroy do
member do
post :cancel
end
end
resources :tasks, only: :index
end
resource :profile, only: [:show, :update]
resources :videos, only: [] do

View File

@@ -0,0 +1,14 @@
class CreateTaskRequests < ActiveRecord::Migration[6.0]
def change
create_table :task_requests do |t|
t.references :project
t.text :description
t.datetime :deadline
t.string :time_allowed
t.text :additional_notes
t.integer :status, default: 0
t.timestamps
end
end
end

View File

@@ -0,0 +1,5 @@
class AddDeliverableUrlToTaskRequests < ActiveRecord::Migration[6.0]
def change
add_column :task_requests, :deliverable_url, :string
end
end

View File

@@ -0,0 +1,5 @@
class AddUserEmailToTaskRequests < ActiveRecord::Migration[6.0]
def change
add_column :task_requests, :user_email, :string
end
end

View File

@@ -0,0 +1,14 @@
class AddSecondGuardianFieldsToTalentReleases < ActiveRecord::Migration[6.0]
def change
add_column :talent_releases, :guardian_2_first_name, :string
add_column :talent_releases, :guardian_2_last_name, :string
add_column :talent_releases, :guardian_2_email, :string
add_column :talent_releases, :guardian_2_phone, :string
add_column :talent_releases, :guardian_2_address_street1, :string
add_column :talent_releases, :guardian_2_address_street2, :string
add_column :talent_releases, :guardian_2_address_city, :string
add_column :talent_releases, :guardian_2_address_state, :string
add_column :talent_releases, :guardian_2_address_zip, :string
add_column :talent_releases, :guardian_2_address_country, :string
end
end

View File

@@ -1503,7 +1503,17 @@ CREATE TABLE public.talent_releases (
person_first_name character varying,
person_last_name character varying,
guardian_first_name character varying,
guardian_last_name character varying
guardian_last_name character varying,
guardian_2_first_name character varying,
guardian_2_last_name character varying,
guardian_2_email character varying,
guardian_2_phone character varying,
guardian_2_address_street1 character varying,
guardian_2_address_street2 character varying,
guardian_2_address_city character varying,
guardian_2_address_state character varying,
guardian_2_address_zip character varying,
guardian_2_address_country character varying
);
@@ -1526,6 +1536,44 @@ CREATE SEQUENCE public.talent_releases_id_seq
ALTER SEQUENCE public.talent_releases_id_seq OWNED BY public.talent_releases.id;
--
-- Name: task_requests; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.task_requests (
id bigint NOT NULL,
project_id bigint,
description text,
deadline timestamp without time zone,
time_allowed character varying,
additional_notes text,
status integer DEFAULT 0,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
deliverable_url character varying,
user_email character varying
);
--
-- Name: task_requests_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.task_requests_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: task_requests_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.task_requests_id_seq OWNED BY public.task_requests.id;
--
-- Name: terms; Type: TABLE; Schema: public; Owner: -
--
@@ -2054,6 +2102,13 @@ ALTER TABLE ONLY public.tags ALTER COLUMN id SET DEFAULT nextval('public.tags_id
ALTER TABLE ONLY public.talent_releases ALTER COLUMN id SET DEFAULT nextval('public.talent_releases_id_seq'::regclass);
--
-- Name: task_requests id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.task_requests ALTER COLUMN id SET DEFAULT nextval('public.task_requests_id_seq'::regclass);
--
-- Name: terms id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -2398,6 +2453,14 @@ ALTER TABLE ONLY public.talent_releases
ADD CONSTRAINT talent_releases_pkey PRIMARY KEY (id);
--
-- Name: task_requests task_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.task_requests
ADD CONSTRAINT task_requests_pkey PRIMARY KEY (id);
--
-- Name: terms terms_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -3036,6 +3099,13 @@ CREATE INDEX index_talent_releases_on_term_id ON public.talent_releases USING bt
CREATE INDEX index_talent_releases_on_territory_id ON public.talent_releases USING btree (territory_id);
--
-- Name: index_task_requests_on_project_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_task_requests_on_project_id ON public.task_requests USING btree (project_id);
--
-- Name: index_unreleased_appearances_on_video_id; Type: INDEX; Schema: public; Owner: -
--
@@ -3800,11 +3870,14 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200430190412'),
('20200507110804'),
('20200512161738'),
('20200518200245'),
('20200519191908'),
('20200526113516'),
('20200603090419'),
('20200606044747'),
('20200610085411'),
('20200610140459'),
('20200610143327'),
('20200612121539'),
('20200615131722'),
('20200615133602'),
@@ -3812,6 +3885,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200619081446'),
('20200619085823'),
('20200619134853'),
('20200622180507');
('20200622180507'),
('20200625144713');

View File

@@ -57,6 +57,8 @@ RSpec.describe AccountsController, type: :controller do
expect {
post :create, params: params
}.to have_enqueued_job(SubmitHubspotFormJob).with(
"John",
"Doe",
"test_user+1@test.com",
"Test Dev account",
i_m_interested_in: "DirectME"

View File

@@ -0,0 +1,68 @@
require "rails_helper"
RSpec.describe Admin::TaskRequestsController, type: :controller do
render_views
let!(:current_user) { create(:user, :admin) }
before do
sign_in(current_user)
end
describe "#index" do
it "returns a successful response" do
get :index
expect(response).to be_successful
end
end
describe "#edit" do
let(:task_request) { create(:task_request) }
it "returns a successful response" do
get :edit, params: { id: task_request }
expect(response).to be_successful
end
it "assigns task request" do
get :edit, params: { id: task_request }
expect(assigns(:task_request)).to eq task_request
end
end
describe "#update" do
let(:task_request) { create(:task_request) }
it "redirects to task requests page" do
patch :update, params: { id: task_request, task_request: update_params }
expect(response).to be_redirect
expect(response).to redirect_to admin_task_requests_path
end
it "sets a flash notice" do
patch :update, params: { id: task_request, task_request: update_params }
expect(flash.notice).to eq "The task request has been updated successfully"
end
it "updates task request" do
patch :update, params: { id: task_request, task_request: update_params }
expect(task_request.reload.status).to eq("completed")
expect(task_request.reload.deliverable_url).to eq("example.com/deliverables")
end
end
private
def update_params
{
status: "completed",
deliverable_url: "example.com/deliverables"
}
end
end

View File

@@ -37,23 +37,26 @@ RSpec.describe Api::AppearanceReleasesController, type: :controller do
it 'includes photos' do
project = create(:project, account_id: current_user.primary_account.id)
appearance_release = create(:appearance_release, person_first_name: 'Release', person_last_name: 'Name', project: project)
appearance_release = create(:appearance_release,
:with_person_photo, :with_guardian_photo, :with_guardian_2_photo,
project: project)
sign_in_to_api(current_user)
get :show, params: { id: appearance_release.id }
photo = appearance_release.person_photo
data = {
'id' => photo.id.to_s,
'type' => 'active_storage_attachment',
'attributes' => {
'content_type' => photo.content_type,
'filename' => photo.filename.to_s,
'url' => photo_path_for(photo),
'thumbnail_url' => photo_variant_path_for(photo, '150x150')
[appearance_release.person_photo, appearance_release.guardian_photo, appearance_release.guardian_2_photo].each do |photo|
data = {
'id' => photo.id.to_s,
'type' => 'active_storage_attachment',
'attributes' => {
'content_type' => photo.content_type,
'filename' => photo.filename.to_s,
'url' => photo_path_for(photo),
'thumbnail_url' => photo_variant_path_for(photo, '150x150')
}
}
}
expect(response_body_included_attributes).to include(data)
expect(response_body_included_attributes).to include(data)
end
end
end
@@ -184,7 +187,46 @@ RSpec.describe Api::AppearanceReleasesController, type: :controller do
expect(appearance_release.guardian_photo).to be_attached
end
it 'returns 201 for minor without second guardian photo' do
post :create, params: @parameters.deep_merge(appearance_release: {
minor: true,
guardian_2_name: 'Guardian 2 Name',
guardian_2_phone: '101010',
})
expect(response.status).to eq 201
expect(AppearanceRelease.last.signature).to be_attached
expect(AppearanceRelease.last.guardian_2_photo).not_to be_attached
end
it 'returns 201 for minor with second guardian photo' do
post :create, params: @parameters.deep_merge(appearance_release: {
minor: true,
guardian_2_name: 'Guardian 2 Name',
guardian_2_phone: '101010',
guardian_2_photo: {
io: guardian_photo_base64,
filename: 'guardian_2_photo.jpeg'
}
})
expect(response.status).to eq 201
appearance_release = AppearanceRelease.last
photo = appearance_release.guardian_2_photo
data = {
'id' => photo.id.to_s,
'type' => 'active_storage_attachment',
'attributes' => {
'content_type' => photo.content_type,
'filename' => photo.filename.to_s,
'url' => photo_path_for(photo),
'thumbnail_url' => photo_variant_path_for(photo, '150x150')
}
}
expect(response_body_included_attributes).to include(data)
expect(appearance_release.signature).to be_attached
expect(appearance_release.guardian_2_photo).to be_attached
end
end
private

View File

@@ -32,26 +32,28 @@ RSpec.describe Api::TalentReleasesController, type: :controller do
end
it 'includes photos' do
tested_release = create("talent_release_with_photo", person_name: 'Release 1', project: project)
project = create(:project, account_id: current_user.primary_account.id)
talent_release = create(:talent_release,
:with_guardian_photo, :with_guardian_2_photo,
project: project)
sign_in_to_api(current_user)
get :show, params: { id: tested_release.id }
sign_in_to_api(current_user)
get :show, params: { id: talent_release.id }
tested_release.photos.each do |photo|
data = {
'id' => photo.id.to_s,
'type' => 'active_storage_attachment',
'attributes' => {
'content_type' => photo.content_type,
'filename' => photo.filename.to_s,
'url' => photo_path_for(photo),
'thumbnail_url' => photo_variant_path_for(photo, '150x150')
}
}
expect(response_body_included_attributes).to include(data)
end
end
[talent_release.photos, talent_release.guardian_photo, talent_release.guardian_2_photo].flatten.each do |photo|
data = {
'id' => photo.id.to_s,
'type' => 'active_storage_attachment',
'attributes' => {
'content_type' => photo.content_type,
'filename' => photo.filename.to_s,
'url' => photo_path_for(photo),
'thumbnail_url' => photo_variant_path_for(photo, '150x150')
}
}
expect(response_body_included_attributes).to include(data)
end
end
end
describe '#create' do
@@ -180,6 +182,47 @@ RSpec.describe Api::TalentReleasesController, type: :controller do
expect(talent_release.signature).to be_attached
expect(talent_release.guardian_photo).to be_attached
end
it 'returns 201 for minor without second guardian photo' do
post :create, params: @parameters.deep_merge(talent_release: {
minor: true,
guardian_2_name: 'Guardian 2 Name',
guardian_2_phone: '101010',
})
expect(response.status).to eq 201
expect(TalentRelease.last.signature).to be_attached
expect(TalentRelease.last.guardian_2_photo).not_to be_attached
end
it 'returns 201 for minor with second guardian photo' do
post :create, params: @parameters.deep_merge(talent_release: {
minor: true,
guardian_2_name: 'Guardian 2 Name',
guardian_2_phone: '101010',
guardian_2_photo: {
io: guardian_photo_base64,
filename: 'guardian_2_photo.jpeg'
}
})
expect(response.status).to eq 201
talent_release = TalentRelease.last
photo = talent_release.guardian_2_photo
data = {
'id' => photo.id.to_s,
'type' => 'active_storage_attachment',
'attributes' => {
'content_type' => photo.content_type,
'filename' => photo.filename.to_s,
'url' => photo_path_for(photo),
'thumbnail_url' => photo_variant_path_for(photo, '150x150')
}
}
expect(response_body_included_attributes).to include(data)
expect(talent_release.signature).to be_attached
expect(talent_release.guardian_2_photo).to be_attached
end
end
private

View File

@@ -7,6 +7,7 @@ RSpec.describe StreamNotificationsController, type: :controller do
let(:active_status) { {type: "video.live_stream.active", object: { id: "mux_stream" }} }
let(:disconnected_status) { {type: "video.live_stream.disconnected", object: { id: "mux_stream" }} }
let(:idle_status) { {type: "video.live_stream.idle", object: { id: "mux_stream" }} }
let(:idle_status_for_unknown_broadcast) { {type: "video.live_stream.idle", object: { id: "unknown-id" }} }
let(:asset_ready) { {
type: "video.asset.static_renditions.ready",
object: { id: "asset_uid" },
@@ -59,6 +60,12 @@ RSpec.describe StreamNotificationsController, type: :controller do
expect(BroadcastsChannel).to have_received(:stream_recording_ready)
end
it "returns OK response even for non-existing broadcast" do
post :create, params: idle_status_for_unknown_broadcast
expect(response).to be_successful
end
end
after do

View File

@@ -0,0 +1,140 @@
require 'rails_helper'
RSpec.describe TaskRequestsController, type: :controller do
render_views
let(:user) { create(:user) }
let(:account) { user.primary_account }
let(:project) { create(:project, account: user.primary_account) }
before do
sign_in user
end
describe "#index" do
it "responds successfully" do
get :index, params: { project_id: project }
expect(response).to be_successful
end
it "renders splash page if there are no task requests" do
get :index, params: { project_id: project }
expect(response.body).to have_link "Create Task Request"
expect(response.body).to have_link schedule_demo
end
it "renders task requests table if there are task requests" do
create(:task_request, project: project, description: "Another Request")
get :index, params: { project_id: project }
expect(response.body).to have_link "Create Task Request"
expect(response.body).to have_content "Pending"
end
context "when there are many records" do
it "paginates the table" do
create_list(:task_request, 20, project: project)
get :index, params: { project_id: project }
expect(response.body).to have_link("2", href: project_task_requests_path(project, page: 2))
end
end
end
describe "#new" do
it "responds successfully" do
get :new, params: { project_id: project }
expect(response).to be_successful
expect(assigns(:task_request)).to be_a_new(TaskRequest)
expect(response).to render_template(:new)
end
end
describe "#create" do
it "does create a new record" do
expect {
post :create, params: { project_id: project.id, task_request: task_request_params }
}.to change(TaskRequest, :count)
end
it "logs an event" do
expect {
post :create, params: { project_id: project.id, task_request: task_request_params }
}.to have_enqueued_job(TrackAnalyticsJob).with(user, account, :track_create_task_request, user_agent: "Rails Testing", user_ip: "0.0.0.0")
end
it "submits data to hubspot form" do
expect {
post :create, params: { project_id: project.id, task_request: task_request_params }
}.to have_enqueued_job(SubmitHubspotTaskRequestFormJob)
end
end
describe "#update" do
let!(:task_request) { create(:task_request, project: project, description: "My description" ) }
it "updates task request" do
patch :update, params: { project_id: project.id, id: task_request.id, task_request: update_params }
expect(task_request.reload.description).to eq("This is updated description")
end
end
describe "#show" do
let!(:task_request) { create(:task_request, project: project, description: "Task Request") }
it "responds successfully" do
get :show, params: { project_id: project.id, id: task_request.id }
expect(response).to be_successful
expect(assigns(:task_request)).to eq(task_request)
end
it "renders content" do
get :show, params: { project_id: project.id, id: task_request.id }
expect(response.body).to have_content "Task Request"
expect(response.body).to have_content "pending"
end
end
describe "#cancel" do
let!(:task_request) { create(:task_request, project: project, description: "Task to be cancelled") }
it "responds with redirect" do
post :cancel, params: { project_id: project.id, id: task_request.id }
expect(response).to be_redirect
expect(response).to redirect_to(project_task_requests_path(project))
expect(flash.notice).not_to be_nil
end
it "updates the status to 'cancelled'" do
expect {
post :cancel, params: { project_id: project.id, id: task_request.id }
}.to change { task_request.reload.status }.from("pending").to("cancelled")
end
end
private
def task_request_params
attributes = attributes_for(:task_request).except(:status, :user_email)
files = 2.times.map { Rack::Test::UploadedFile.new(file_fixture("location_photo.png"), "image/png") }
attributes.merge({ files: files })
end
def update_params
{ description: "This is updated description" }
end
def schedule_demo
t 'task_requests.splash.actions.book_demo'
end
end

View File

@@ -0,0 +1,40 @@
require 'rails_helper'
RSpec.describe TasksController, type: :controller do
render_views
let(:user) { create(:user) }
let(:account) { user.primary_account }
let(:project) { create(:project, account: user.primary_account) }
before do
sign_in user
end
describe "#index" do
it "responds successfully" do
get :index, params: { project_id: project }
expect(response).to be_successful
end
it "renders content" do
create(:task_request, :completed, project: project, description: "Another Request")
get :index, params: { project_id: project }
expect(response.body).to have_content "Completed"
expect(response.body).to have_link "View Deliverable"
end
context "when there are many records" do
it "paginates the table" do
create_list(:task_request, 20, :completed, project: project)
get :index, params: { project_id: project }
expect(response.body).to have_link("2", href: project_tasks_path(project, page: 2))
end
end
end
end

View File

@@ -58,10 +58,7 @@ FactoryBot.define do
guardian_address_state "State"
guardian_address_zip "ZIP"
guardian_address_country "Country"
guardian_photo do
path = Rails.root.join("spec", "fixtures", "files", "pratt.jpg")
Rack::Test::UploadedFile.new(path, "image/jpeg")
end
with_guardian_photo
end
trait :without_person_photo do
@@ -74,6 +71,20 @@ FactoryBot.define do
end
end
trait :with_guardian_photo do
guardian_photo do
path = Rails.root.join("spec", "fixtures", "files", "pratt.jpg")
Rack::Test::UploadedFile.new(path, "image/jpeg")
end
end
trait :with_guardian_2_photo do
guardian_2_photo do
path = Rails.root.join("spec", "fixtures", "files", "pratt.jpg")
Rack::Test::UploadedFile.new(path, "image/jpeg")
end
end
trait :with_person_photo_only do
end

View File

@@ -35,12 +35,23 @@ FactoryBot.define do
guardian_first_name "Jamie"
guardian_last_name "Doe"
guardian_phone "123-555-1234"
with_guardian_photo
end
trait :with_guardian_photo do
guardian_photo do
path = Rails.root.join("spec", "fixtures", "files", "pratt.jpg")
Rack::Test::UploadedFile.new(path, "image/jpeg")
end
end
trait :with_guardian_2_photo do
guardian_2_photo do
path = Rails.root.join("spec", "fixtures", "files", "pratt.jpg")
Rack::Test::UploadedFile.new(path, "image/jpeg")
end
end
factory :talent_release_with_contract_template do
after(:build) do |talent_release, _|
talent_release.contract_template = build(:talent_release_contract_template)

View File

@@ -0,0 +1,20 @@
FactoryBot.define do
factory :task_request do
association :project
user_email 'test@email.com'
deadline { 10.days.from_now }
time_allowed 5
description "Task request"
additional_notes "Additional notes"
status 0
trait :completed do
deliverable_url "example.com/deliverables"
status 1
end
trait :with_files do
files { [Rack::Test::UploadedFile.new('spec/fixtures/files/contract.pdf', 'application/pdf')] }
end
end
end

View File

@@ -0,0 +1,108 @@
require "rails_helper"
feature "Admin managing task requests" do
let(:current_user) { create(:user, admin: true, email: "user@test.com") }
let(:project) { create(:project, account: current_user.primary_account, name: "Test Project") }
before do
sign_in current_user
end
scenario "admin should see View action for task request in Manage dropdown", js: true do
create(:task_request)
visit admin_task_requests_path
click_on 'Manage'
expect(page).to have_content 'View'
end
scenario "admin can open detail view of task request", js: true do
task_request = create(:task_request, :with_files)
visit admin_task_requests_path
click_on 'Manage'
click_link 'View'
switch_to_window(windows.last)
expect(page).to have_content 'Account Name'
expect(page).to have_content task_request.project.account.name
expect(page).to have_content 'Project Name'
expect(page).to have_content task_request.project.name
expect(page).to have_content 'Description'
expect(page).to have_content task_request.description
expect(page).to have_content 'Created At'
expect(page).to have_content task_request.created_at
expect(page).to have_content 'User Email'
expect(page).to have_content task_request.user_email
expect(page).to have_content 'Deadline'
expect(page).to have_content task_request.deadline
expect(page).to have_content 'Time Allowed'
expect(page).to have_content task_request.time_allowed
expect(page).to have_content 'Additional Notes'
expect(page).to have_content task_request.additional_notes
expect(page).to have_content 'Status'
expect(page).to have_content task_request.status
expect(page).to have_content 'Files'
task_request.files.each do |file|
expect(page).to have_content file.blob.filename
end
end
scenario "no files attached label is shown if there are no files attached to the task request", js:true do
create(:task_request)
visit admin_task_requests_path
click_on 'Manage'
click_link 'View'
switch_to_window(windows.last)
expect(page).to have_content 'Attached files will appear here.'
end
scenario "task requests table is visible" do
visit admin_task_requests_path
expect(page).to have_content "Task ID"
expect(page).to have_content "Account Name"
expect(page).to have_content "Project Name"
expect(page).to have_content "Created On"
expect(page).to have_content "Deadline"
expect(page).to have_content "Time Allowed"
expect(page).to have_content "Status"
end
scenario "sees list of task requests" do
visit admin_task_requests_path
expect(page).to have_content no_task_requests_label
task_request = create(:task_request)
visit admin_task_requests_path
expect(page).not_to have_content no_task_requests_label
expect(page).to have_content task_request.id
expect(page).to have_content task_request.project.account.name
expect(page).to have_content task_request.project.name
expect(page).to have_content task_request.created_at.try(:strftime, '%D')
expect(page).to have_content task_request.deadline.try(:strftime, '%D')
expect(page).to have_content task_request.time_allowed
expect(page).to have_content task_request.status.capitalize
end
private
def no_task_requests_label
"Task requests will appear here"
end
end

View File

@@ -0,0 +1,92 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.feature 'User creates task request', type: :feature do
let(:current_user) { create(:user, :manager) }
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
before do
sign_in(current_user)
end
scenario 'creating a new task request' do
visit new_project_task_request_path(project)
fill_in description_field, with: 'Description of the task'
fill_in deadline_field, with: '2020-06-24'
fill_in time_allowed_field, with: '30'
fill_in additional_notes_field, with: 'Additional note about the task'
click_on 'Create Task request'
expect(page).to have_content task_created_message
end
scenario 'user can view task request details' do
create(:task_request, project: project, description: 'Description of the task', deadline: '2020-07-23', time_allowed: '10', additional_notes: 'Additional note about the task')
visit project_task_request_path(project, TaskRequest.first)
expect(page).to have_content('Description of the task')
expect(page).to have_content('2020-07-23')
expect(page).to have_content('10')
expect(page).to have_content('Additional note about the task')
end
scenario 'user can update existing task request' do
create(:task_request, project: project, description: 'Description of the task', deadline: '2020-08-23', time_allowed: '10', additional_notes: 'Additional note about the task')
visit edit_project_task_request_path(project, TaskRequest.first)
fill_in deadline_field, with: '2020-07-01'
fill_in time_allowed_field, with: '13'
click_on 'Update Task request'
expect(page).to have_content('13')
expect(page).to have_content('07/01/20')
end
scenario 'user can cancel a task request' do
create(:task_request, project: project, description: 'Description of the task', deadline: '2020-08-23', time_allowed: '10', additional_notes: 'Additional note about the task')
visit project_task_requests_path(project)
click_on 'Manage'
click_link 'Cancel'
expect(page).to have_content('Cancelled')
end
scenario 'user can view completed tasks' do
create_list(:task_request, 5, project: project, status: 'completed')
create_list(:task_request, 5, project: project, status: 'pending')
visit project_tasks_path(project)
expect(page).to have_content('Completed')
expect(page).not_to have_content('Pending')
end
private
def description_field
t "task_requests.form.labels.description"
end
def deadline_field
t "task_requests.form.labels.deadline"
end
def time_allowed_field
t "task_requests.form.labels.time_allowed"
end
def additional_notes_field
t "task_requests.form.labels.additional_notes"
end
def task_created_message
t 'task_requests.create.success_message'
end
end

View File

@@ -1,97 +1,138 @@
require "rails_helper"
# frozen_string_literal: true
feature "User managing broadcasts" do
require 'rails_helper'
feature 'User managing broadcasts' do
let(:current_user) { create(:user, :manager) }
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
context "managing broadcasts" do
context 'managing broadcasts' do
before do
sign_in current_user
allow(MuxLiveStream).to receive(:new).and_return(double(id: "id", key: "key", playback_id: "playback_id"))
allow(MuxLiveStream).to receive(:new).and_return(double(id: 'id', key: 'key', playback_id: 'playback_id'))
end
scenario "creating and deleting a broadcast", js: true do
scenario 'creating and deleting a broadcast', js: true do
visit new_project_broadcast_path(project)
by "filling out the form" do
fill_in broadcast_name_field, with: "My Broadcast"
by 'filling out the form' do
fill_in broadcast_name_field, with: 'My Broadcast'
end
click_button "Create Live Stream"
expect(page).to have_content("A live stream has been created")
click_on "Manage"
expect(page).to have_link("Copy Stream URL", exact: true)
expect(page).to have_link("Copy Stream Key", exact: true)
expect(page).to have_link("View", exact: true)
expect(page).to have_link("Delete", exact: true)
click_button 'Create Live Stream'
expect(page).to have_content('A live stream has been created')
click_on 'Manage'
expect(page).to have_link('Copy Stream URL', exact: true)
expect(page).to have_link('Copy Stream Key', exact: true)
expect(page).to have_link('View', exact: true)
expect(page).to have_link('Delete', exact: true)
it_also "Deletes the broadcast" do
it_also 'Deletes the broadcast' do
allow_any_instance_of(Broadcast).to receive(:destroy_mux_live_stream).and_return(true)
accept_alert do
click_link "Delete"
click_link 'Delete'
end
expect(page).to have_content("A live stream has been deleted")
expect(page).not_to have_content("My Broadcast")
expect(page).to have_content('A live stream has been deleted')
expect(page).not_to have_content('My Broadcast')
end
end
scenario "visit show page of broadcast", js: true do
scenario 'visit show page of broadcast', js: true do
broadcast = create(:broadcast, :with_stream, :with_files, project: project)
recording = create(:broadcast_recording, broadcast: broadcast)
visit project_broadcast_path(project, broadcast)
expect(page).to have_content("Live stream is waiting to begin.")
expect(page).to have_content("Copy URL")
expect(page).to have_content('Live stream is waiting to begin.')
expect(page).to have_content('Copy URL')
within "#files" do
expect(page).to have_content("contract.pdf")
within '#files' do
expect(page).to have_content('contract.pdf')
end
click_on "Previous Sessions"
click_on 'Previous Sessions'
expect(page).to have_content(recording.download_file_name)
end
scenario "form will not submit if user clicks Add files without selected files", js: true do
scenario 'user can go back and forth between live session and previous sessions', js: true do
broadcast = create(:broadcast, :with_stream, :with_files, project: project)
recording = create(:broadcast_recording, broadcast: broadcast)
visit project_broadcast_path(project, broadcast)
expect(page).to have_content broadcast.name.titleize, count: 1
expect(page).to have_content recording.download_file_name, count: 0
click_on switch_view_dropdown
expect(page).to have_content broadcast.name.titleize, count: 2
expect(page).to have_content recording.download_file_name, count: 1
live_stream_nav_item = page.find('.dropdown-item', text: broadcast.name.titleize)
recording_nav_item = page.find('.dropdown-item', text: recording.download_file_name)
expect(live_stream_nav_item[:class].include?('active')).to eq true
expect(recording_nav_item[:class].include?('active')).to eq false
click_on recording.download_file_name
expect(page).to have_content broadcast.name.titleize, count: 1
expect(page).to have_content recording.download_file_name, count: 0
expect(live_stream_nav_item[:class].include?('active')).to eq false
expect(recording_nav_item[:class].include?('active')).to eq true
click_on switch_view_dropdown
click_on broadcast.name.titleize
expect(page).to have_content broadcast.name.titleize, count: 1
expect(page).to have_content recording.download_file_name, count: 0
# Page is reloaded, we need to get dropdown items again
live_stream_nav_item = page.find('.dropdown-item', text: broadcast.name.titleize, visible: :all)
recording_nav_item = page.find('.dropdown-item', text: recording.download_file_name, visible: :all)
expect(live_stream_nav_item[:class].include?('active')).to eq true
expect(recording_nav_item[:class].include?('active')).to eq false
end
scenario 'form will not submit if user clicks Add files without selected files', js: true do
broadcast = create(:broadcast, :with_stream, :with_files, project: project)
visit project_broadcast_path(project, broadcast)
expect(page).to have_content("Live stream is waiting to begin.")
expect(page).to have_content('Live stream is waiting to begin.')
expect(page).to have_content add_file_button
click_on add_file_button
end
scenario "visit multi-view broadcast page", js: true do
broadcast_one = create(:broadcast, :with_stream, :with_files, name: "Broadcast 1", project: project)
broadcast_two = create(:broadcast, :with_stream, :with_files, name: "Broadcast 2", project: project)
scenario 'visit multi-view broadcast page', js: true do
broadcast_one = create(:broadcast, :with_stream, :with_files, name: 'Broadcast 1', project: project)
broadcast_two = create(:broadcast, :with_stream, :with_files, name: 'Broadcast 2', project: project)
visit project_broadcasts_path(project)
click_checkboxes
new_window = window_opened_by { click_link "Multi-View" }
new_window = window_opened_by { click_link 'Multi-View' }
within_window new_window do
expect(page).to have_content("Switch View")
expect(page).to have_content switch_view_dropdown
click_on "Switch View"
expect(page).to have_link("Broadcast 1")
expect(page).to have_link("Broadcast 2")
click_on switch_view_dropdown
expect(page).to have_link('Broadcast 1')
expect(page).to have_link('Broadcast 2')
within "#files" do
click_on "Broadcast 1"
expect(page).to have_content("contract.pdf")
within '#files' do
click_on 'Broadcast 1'
expect(page).to have_content('contract.pdf')
click_on "Broadcast 2"
expect(page).to have_content("contract.pdf")
click_on 'Broadcast 2'
expect(page).to have_content('contract.pdf')
end
end
end
end
end
private
def add_file_button
@@ -99,11 +140,15 @@ feature "User managing broadcasts" do
end
def broadcast_name_field
"broadcast[name]"
'broadcast[name]'
end
def click_checkboxes
all('input[type="checkbox"]')[0].click
all('input[type="checkbox"]')[1].click
end
def switch_view_dropdown
'Switch View'
end
end

View File

@@ -62,6 +62,47 @@ feature "User managing talent releases" do
expect(page).to have_content("Your release was successfully submitted. Thank you.")
end
scenario "creating a release for a minor with two guardians", js: true do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_talent_release_path(project.account, project, contract_template)
expect(page).not_to have_content guardian_information_heading.upcase
expect(page).not_to have_content guardian_2_information_heading.upcase
expect(page).not_to have_content guardian_photo_heading.upcase
expect(page).not_to have_content guardian_2_photo_heading.upcase
page.check person_is_minor_checkbox
expect(page).to have_content guardian_information_heading.upcase
expect(page).to have_content guardian_2_information_heading.upcase
expect(page).to have_content guardian_photo_heading.upcase
expect(page).to have_content guardian_2_photo_heading.upcase
fill_in person_first_name_field, with: "Jane"
fill_in person_last_name_field, with: "Doe"
fill_in person_address_field, with: "123 Test Lane, New York, NY 10000"
fill_in person_phone_field, with: "555-555-5555"
fill_in person_email_field, with: "jane.doe@test.com"
fill_in guardian_first_name_field, with: "Guardian"
fill_in guardian_last_name_field, with: "Name"
fill_in guardian_phone_field, with: "001101"
fill_in guardian_2_first_name_field, with: "Second"
fill_in guardian_2_last_name_field, with: "Guardian"
drop_file Rails.root.join(file_fixture("person_photo.png")), type: :dropzone
attach_file guardian_photo_field, file_fixture("hemsworth.jpeg"), visible: :all
attach_file guardian_2_photo_field, file_fixture("person_photo.png"), visible: :all
draw_signature file_fixture("signature.png"), "talent_release_signature_base64"
click_button submit_button
expect(page).to have_content success_submit_message
expect(TalentRelease.last.guardian_2_photo.attached?).to eq true
expect(TalentRelease.last.guardian_2_name).to eq "Second Guardian"
end
end
context "when signed in" do
@@ -125,6 +166,43 @@ feature "User managing talent releases" do
expect(page).to have_photo("person_photo.png")
end
scenario "creating a release for minor with two guardians", js: true do
visit new_project_talent_release_path(project)
expect(page).not_to have_content guardian_photo_heading
expect(page).not_to have_content guardian_2_photo_heading
page.check person_is_minor_checkbox
expect(page).to have_content guardian_photo_heading
expect(page).to have_content guardian_2_photo_heading
fill_in person_first_name_field, with: "John"
fill_in person_last_name_field, with: "Doe"
fill_in guardian_first_name_field, with: "Guardian"
fill_in guardian_last_name_field, with: "Name"
fill_in guardian_phone_field, with: "01010"
fill_in guardian_2_first_name_field, with: "Second"
fill_in guardian_2_last_name_field, with: "Guardian"
fill_in_exploitable_rights
attach_file contract_field, Rails.root.join(file_fixture("contract.pdf")), visible: false
drop_file Rails.root.join(file_fixture("person_photo.png")), type: :dropzone
attach_file guardian_photo_field, Rails.root.join(file_fixture("hemsworth.jpeg")), visible: false
attach_file guardian_2_photo_field, Rails.root.join(file_fixture("pratt.jpg")), visible: false
click_button create_release_button
expect(page).to have_content create_release_notice
expect(page).to have_photo("person_photo.png")
expect(TalentRelease.last.guardian_2_photo.attached?).to eq true
expect(TalentRelease.last.guardian_2_name).to eq "Second Guardian"
end
scenario "updating an existing release" do
talent_release = create(:talent_release, project: project)
@@ -301,6 +379,14 @@ feature "User managing talent releases" do
"Guardian last name"
end
def guardian_2_first_name_field
"talent_release[guardian_2_first_name]"
end
def guardian_2_last_name_field
"talent_release[guardian_2_last_name]"
end
def guardian_phone_field
"Guardian phone"
end
@@ -309,6 +395,10 @@ feature "User managing talent releases" do
"talent_release[guardian_photo]"
end
def guardian_2_photo_field
"talent_release[guardian_2_photo]"
end
def have_photo_button
have_selector(".take-photo-button")
end
@@ -387,4 +477,32 @@ feature "User managing talent releases" do
select "Other", from: "Restriction"
fill_in "Describe other restrictions", with: "Test"
end
def guardian_information_heading
t 'public.talent_releases.new.guardian_info.heading'
end
def guardian_2_information_heading
t 'public.talent_releases.new.guardian_2_info.heading'
end
def guardian_photo_heading
t 'public.talent_releases.new.guardian_photo.heading'
end
def guardian_2_photo_heading
t 'public.talent_releases.new.guardian_2_photo.heading'
end
def submit_button
t 'shared.submit_release_long'
end
def success_submit_message
"Your release was successfully submitted. Thank you."
end
def contract_field
"talent_release[contract]"
end
end

View File

@@ -0,0 +1,123 @@
require "rails_helper"
feature "User managing task requests" do
let(:current_user) { create(:user) }
let(:project) { create(:project, account: current_user.primary_account) }
before :each do
sign_in current_user
end
scenario "splash page is shown if there are no task requests" do
visit project_task_requests_path(project)
expect(page).to have_content schedule_demo
end
scenario "task requests table is visible" do
create(:task_request, project: project, description: 'Short Desc')
visit project_task_requests_path(project)
expect(page).to have_content "Created On"
expect(page).to have_content "Deadline"
expect(page).to have_content description_column
expect(page).to have_content "Time Allowed"
expect(page).to have_content "Status"
end
scenario "sees list of task requests" do
task_request = create(:task_request, project: project)
visit project_task_requests_path(project)
expect(page).not_to have_content no_task_requests_label
expect(page).to have_content task_request.created_at.try(:strftime, '%D')
expect(page).to have_content task_request.deadline.try(:strftime, '%D')
expect(page).to have_content task_request.time_allowed
expect(page).to have_content task_request.status.capitalize
end
scenario "full description is shown if description text is not truncated" do
visit project_task_requests_path(project)
task_request = create(:task_request, project: project, description: 'Short Desc')
visit project_task_requests_path(project)
expect(page).to have_content task_request.description
end
scenario "truncated description is shown if description text is too long" do
visit project_task_requests_path(project)
task_request = create(:task_request,
project: project,
description: long_description_text)
visit project_task_requests_path(project)
expect(page).not_to have_content task_request.description
truncated_text = "#{task_request.description[0..26]}...read more"
expect(page).to have_content truncated_text
end
scenario "full description is shown when user hovers over read more link in description colum", js: true do
visit project_task_requests_path(project)
task_request = create(:task_request,
project: project,
description: long_description_text)
visit project_task_requests_path(project)
page.execute_script '$("a[data-toggle=popover]").trigger("mouseover")'
expect(page).to have_content task_request.description
end
scenario "user does not see open deliverable action in manage dropdown if task status is not completed" do
task_request = create(:task_request, project: project)
visit project_task_requests_path(project)
click_on manage_button
expect(page).not_to have_content open_deliverable_action_label
end
scenario "user can click deliverable action in manage dropdown if task status is completed", js: true do
create(:task_request, project: project, status: "completed", deliverable_url: "/")
visit project_task_requests_path(project)
click_on manage_button
expect(page).to have_content open_deliverable_action_label
click_link open_deliverable_action_label
switch_to_window(windows.last)
expect(page).to have_content add_new_project_label
end
private
def no_task_requests_label
"Task requests will appear here"
end
def manage_button
t "task_requests.task_request.actions.manage"
end
def open_deliverable_action_label
t "task_requests.task_request.actions.open_deliverable"
end
def add_new_project_label
t "projects.index.actions.new"
end
def description_column
t 'task_requests.index.table_headers.task_request_description'
end
def long_description_text
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
end
def schedule_demo
t 'task_requests.splash.actions.book_demo'
end
end

View File

@@ -11,10 +11,12 @@ RSpec.describe SubmitHubspotFormJob, type: :job do
allow(Hubspot::Form).to receive(:new).and_return(form)
allow(form).to receive(:submit).and_return(true)
SubmitHubspotFormJob.perform_now("email@test.com", "My Account")
SubmitHubspotFormJob.perform_now("John", "Doe", "email@test.com", "My Account")
expect(Hubspot::Form).to have_received(:new).with("guid" => "hubspot_form_guid")
expect(form).to have_received(:submit).with(
first_name: "John",
last_name: "Doe",
email: "email@test.com",
company: "My Account"
)
@@ -25,9 +27,11 @@ RSpec.describe SubmitHubspotFormJob, type: :job do
allow(Hubspot::Form).to receive(:new).and_return(form)
allow(form).to receive(:submit).and_return(true)
SubmitHubspotFormJob.perform_now("email@test.com", "My Account", additional_param_one: "Foo", additional_param_two: "Bar")
SubmitHubspotFormJob.perform_now("John", "Doe", "email@test.com", "My Account", additional_param_one: "Foo", additional_param_two: "Bar")
expect(form).to have_received(:submit).with(
first_name: "John",
last_name: "Doe",
email: "email@test.com",
company: "My Account",
additional_param_one: "Foo",
@@ -42,7 +46,7 @@ RSpec.describe SubmitHubspotFormJob, type: :job do
allow(Hubspot::Form).to receive(:new).and_return(form)
allow(form).to receive(:submit)
SubmitHubspotFormJob.perform_now("email@test.com", "My Account")
SubmitHubspotFormJob.perform_now("John", "Doe", "email@test.com", "My Account")
expect(form).not_to have_received(:submit)
end

View File

@@ -0,0 +1,36 @@
require 'rails_helper'
RSpec.describe SubmitHubspotTaskRequestFormJob, type: :job do
describe '#perform_now' do
before do
ENV["HUBSPOT_TASK_REQUEST_FORM_GUID"] = "hubspot_task_request_form_guid"
end
it 'submits to the Hubspot API with the right params' do
form = double(:form)
allow(Hubspot::Form).to receive(:new).and_return(form)
allow(form).to receive(:submit).and_return(true)
SubmitHubspotTaskRequestFormJob.perform_now("email@test.com", "https://example.com/admin/task_requests/1")
expect(Hubspot::Form).to have_received(:new).with("guid" => "hubspot_task_request_form_guid")
expect(form).to have_received(:submit).with(
email: "email@test.com",
taskme_url: "https://example.com/admin/task_requests/1"
)
end
context 'when HUBSPOT_TASK_REQUEST_FORM_GUID is not available' do
it 'does not submit to the API' do
ENV["HUBSPOT_TASK_REQUEST_FORM_GUID"] = nil
form = double(:form)
allow(Hubspot::Form).to receive(:new).and_return(form)
allow(form).to receive(:submit)
SubmitHubspotTaskRequestFormJob.perform_now("email@test.com", "https://example.com/admin/task_requests/1")
expect(form).not_to have_received(:submit)
end
end
end
end

View File

@@ -129,11 +129,13 @@ RSpec.describe Account do
Download,
User,
Broadcast,
TaskRequest,
Account,
ZoomMeeting,
MedicalRelease,
MiscRelease,
MatchingRequest
MatchingRequest,
ActionMailbox::InboundEmail # This is Rails model, we are not using it and it is NOT added to the Account#storage_total calculation
]
Rails.application.eager_load!
ActiveRecord::Base.descendants.each do |model|

View File

@@ -0,0 +1,20 @@
require 'rails_helper'
RSpec.describe TaskRequest, type: :model do
describe "associations" do
it { is_expected.to belong_to(:project) }
end
describe "enums" do
it { is_expected.to define_enum_for(:status).with_values([:pending, :completed, :cancelled]) }
end
describe "#order_by_recent" do
subject { described_class }
it { is_expected.to respond_to(:order_by_recent) }
end
describe "#validations" do
it { should validate_numericality_of(:time_allowed).only_integer.is_greater_than_or_equal_to(2) }
end
end