Compare commits

..

8 Commits

Author SHA1 Message Date
bilal
7b319d4247 update structure.sql 2020-06-19 10:30:10 +02:00
bilal
f1e662879d change text 2020-06-19 10:27:49 +02:00
bilal
0cc305302a move notice to the top; change style 2020-06-15 13:03:14 +02:00
Senad Uka
8ad89371b8 Task mvp upstream sync 2020-06-15 11:02:00 +02:00
Senad Uka
9d7e2c044a Upstream sync task me 2020-06-09 06:34:58 +02:00
Senad Uka
88836e937e Task me sync 2020-06-03 07:24:01 +02:00
bilal
e3d4d22a34 Handle QrMatching response - mock 2020-06-02 22:23:19 +02:00
Senad Uka
3690268f83 Sync of the branch 2020-06-01 18:59:15 +02:00
114 changed files with 1323 additions and 808 deletions

View File

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

View File

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

View File

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

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

@@ -6,11 +6,6 @@
@import "dropzone/dist/dropzone";
@import 'bootstrap-datepicker';
// Global styles
label {
text-transform: capitalize;
}
// Wordmarks
.suite-wordmark {
font-weight: normal;
@@ -37,14 +32,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 +53,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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,74 @@
class TaskRequestsController < ApplicationController
layout "project"
before_action :set_project
before_action :build_task_request, only: [:new, :create]
before_action :set_task_request, only: [:show, :edit, :update, :cancel]
def index
@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
redirect_to [@project, :task_requests], notice: t(".notice")
else
render :new
end
end
def show
end
def edit
end
def update
if @task_request.update(task_request_params)
redirect_to [@project, :task_requests], notice: t(".notice")
else
render :edit
end
end
def cancel
@task_request.cancelled!
redirect_to [@project, :task_requests], notice: t(".notice")
end
private
def task_request_params
params.require(:task_request).permit(:description, :deadline, :time_allowed, :additional_notes, files: [])
end
def 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

@@ -13,11 +13,8 @@ class ZoomNotificationsController < ApplicationController
@zoom_meeting.started!
when 'meeting.ended'
@zoom_meeting.ended!
when 'recording.completed'
recording = notification.dig(:payload, :object, :recording_files).first
AttachRecordingToZoomMeetingJob.perform_later(@zoom_meeting, recording, notification['download_token'])
else
Rails.logger.info notification_event
Rails.logger.info notification_type
Rails.logger.info notification
end
@@ -26,20 +23,16 @@ class ZoomNotificationsController < ApplicationController
private
def notification
params.to_unsafe_h
end
def notification_event
notification.dig(:event)
params.dig(:event)
end
def notification_meeting_id
notification.dig(:payload, :object, :id)
params.dig(:payload, :object, :id)
end
def notification_host_id
notification.dig(:payload, :object, :host_id)
params.dig(:payload, :object, :host_id)
end
def set_zoom_meeting

View File

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

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

@@ -7,6 +7,8 @@ module DropzoneHelper
"To Add Audio Files to the release:<br>Drag & Drop Files<br>or<br>Click or Tap here to browse files"
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

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

View File

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

View File

@@ -54,7 +54,7 @@ class Account < ApplicationRecord
Download.where(project: projects),
User.joins(:project_memberships).where(project_memberships: { project: projects }),
Broadcast.where(project: projects),
ZoomMeeting.where(project: projects),
TaskRequest.where(project: projects),
self
])).sum(:byte_size).to_f
end
@@ -79,6 +79,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"
@@ -87,6 +91,8 @@ class Account < ApplicationRecord
"DirectME"
when "releaseme"
"ReleaseME"
when "taskme"
"TaskME"
when "me_suite"
"ME Suite"
end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,6 +22,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
@@ -117,7 +118,7 @@ class Project < ApplicationRecord
current_zoom_meeting = zoom_meetings.active.first
unless current_zoom_meeting.present?
zoom_user = ZoomUser.for_new_meeting
zoom_user = ZoomUser.free.first || ZoomUser.create
current_zoom_meeting = ZoomMeeting.create(zoom_user: zoom_user, project: self)
end

View File

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

View File

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

View File

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

View File

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

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

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

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,6 @@
<% if releasable.model_name == "LocationRelease" %>
<%= description_list_pair "Filming Started On:", releasable&.filming_started_on&.strftime("%D") %>
<%= description_list_pair "Filming Ended On:", releasable&.filming_ended_on&.strftime("%D") %>
<%= description_list_pair "Filming Hours:", releasable&.filming_hours %>
<% end %>
<% if contract_template.fee? %>
<%= description_list_pair "Fee:", number_to_currency(contract_template.fee) %>

View File

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

View File

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

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

View File

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

View File

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

View File

@@ -27,7 +27,11 @@
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :person_company, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
</div>
@@ -41,7 +45,6 @@
<div class="form-row">
<%= form.text_field :filming_started_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %>
<%= form.text_field :filming_ended_on, wrapper_class: "col-sm-6", class: "datepicker-control", readonly: true %>
<%= form.text_field :filming_hours, wrapper_class: "col-sm-12" %>
</div>
<% end %>

View File

@@ -27,7 +27,11 @@
<%= form.text_field :person_first_name, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_last_name, wrapper_class: "col-sm-6" %>
<%= form.phone_field :person_phone, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.email_field :person_email, wrapper_class: "col-sm-6" %>
</div>
<div class="form-row">
<%= form.text_field :person_company, wrapper_class: "col-sm-6" %>
<%= form.text_field :person_title, wrapper_class: "col-sm-6" %>
</div>

View File

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

View File

@@ -0,0 +1,39 @@
<%= errors_summary_for task_request %>
<%= bootstrap_form_with model: model, local: true do |form| %>
<div class="alert alert-notice text-center pl-0 text-md-left mt-4">
<%= 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.text_field :time_allowed, label: t('.labels.time_allowed') %>
<%= 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,33 @@
<tr>
<td>
<%= task_request.created_at.strftime('%D') %>
</td>
<td>
<%= task_request.deadline.try(:strftime, '%D') %>
</td>
<td>
<%= task_request.time_allowed %>
</td>
<td>
<%= task_request.status.titleize %>
</td>
<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,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,38 @@
<%= 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_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="5" class="py-4 text-center text-muted"><%= t(".empty") %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div id="task_requests_pagination" class="mt-3">
<%= will_paginate @task_requests %>
</div>

View File

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

View File

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

View File

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

@@ -93,6 +93,11 @@ en:
application:
header:
sign_out: Sign Out
task_requests:
index:
empty: Task requests will appear here
update:
notice: The task request has been updated successfully
users:
create:
notice: The user was created
@@ -305,8 +310,6 @@ en:
graphics_only_edl_file: If you do not upload a Graphics Only EDL, the software will not generate a Graphics Cue List.
label:
acquired_media_release:
description: Description of licensed property
name: Name of licensed property
person_address: Address
person_address_city: City
person_address_country: Country
@@ -316,8 +319,6 @@ en:
person_address_zip: Zip code
person_company: Company
person_email: Email address
person_first_name: Licensor/Owner first name
person_last_name: Licensor/Owner last name
person_name: Name
person_phone: Phone number
person_title: Title
@@ -331,23 +332,16 @@ en:
address_city: City
address_country: Country
address_state: State
address_street1: Address of Property
address_street1: Address
address_street2: Address (Line 2)
address_zip: Zip code
filming_ended_on: Filming end date
filming_started_on: Filming start date
name: Name of property
person_address_city: City
person_address_country: Country
person_address_state: State
person_address_street1: Address
person_address_street2: Address (Line 2)
person_address_zip: Zip code
person_first_name: Owner first name
person_last_name: Owner last name
material_release:
description: Description of licensed material
name: Name of licensed material
person_address: Address
person_address_city: City
person_address_country: Country
@@ -357,8 +351,6 @@ en:
person_address_zip: Zip code
person_company: Company
person_email: Email address
person_first_name: Licensor/Owner first name
person_last_name: Licensor/Owner last name
person_name: Name
person_phone: Phone number
person_title: Title
@@ -557,7 +549,7 @@ en:
photos:
heading: 4 of 4 Photos
signer_details:
heading: 2 of 4 Owner Details
heading: 2 of 4 Signer Details
index:
actions:
new: Import Release
@@ -591,7 +583,7 @@ en:
photos:
heading: 4 of 4 Photos
signer_details:
heading: 2 of 4 Licensor/Owner Details
heading: 2 of 4 Signer Details
index:
actions:
new: Import Release
@@ -652,7 +644,6 @@ en:
create:
notice: Check your email for password reset instructions
edit:
notice: This password reset URL has expired or is invalid. Try again by clicking "Forgot your password?" below
submit: Save New Password
title: Password Reset
new:
@@ -743,6 +734,7 @@ en:
music_release: Music Releases (%{count})
report: Reports
talent_release: Talent Releases (%{count})
tasks: Tasks
public:
acquired_media_releases:
new:
@@ -754,7 +746,9 @@ en:
legal:
heading: Legal
personal_info:
heading: Licensor/Owner Contact Information
heading: Person Details
personal_info:
heading: Signer's Contact Information
signature:
heading: Signature
appearance_releases:
@@ -793,7 +787,7 @@ en:
new:
cancel: Cancel
contact_info:
heading: Owner Contact Information
heading: Signer Information
filming_info:
heading: Filming Information
legal:
@@ -808,7 +802,7 @@ en:
new:
cancel: Cancel
contact_info:
heading: Licensor/Owner Contact Information
heading: Signer's Contact Information
legal:
heading: Legal
release_info:
@@ -906,6 +900,7 @@ en:
tag_multiple_releases: Add Tag
tag_multiple_releases_form:
submit: Add
task_me: Task
tags:
form:
submit: Add
@@ -941,6 +936,49 @@ 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.
edit:
heading:
Edit Task Request
form:
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 like spend on this task?
info_message: After submitting this task request, you'll be connected via chat with a ME Suite representative.
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_results: Task Results
task_request_status: Status
task_request_time_allowed: Time Allowed
new:
heading: New Task Request
task_request:
actions:
manage: Manage
open_deliverable: Open Deliverable
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

@@ -182,3 +182,10 @@ es:
photos:
guardian_photo:
heading: Guardian Photo (ES)
task_requests:
task_request:
actions:
manage: Manage (ES)
open_deliverable: Open Deliverable (ES)
form:
info_message: After submitting this task request, you'll be connected via chat with a ME Suite representative. (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
@@ -97,6 +98,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

@@ -1,7 +0,0 @@
class AssignAccountNumberAndTypeToZoomUsers < ActiveRecord::DataMigration
def up
ZoomUser.find_each do |zu|
zu.update account_number: ENV.fetch('ZOOM_ACCOUNT_NUMBER'), tier: (ENV['ZOOM_USER_TYPE'] == 'pro' ? 1 : 0)
end
end
end

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

@@ -1,6 +0,0 @@
class AddAccountNumberAndTypeToZoomUsers < ActiveRecord::Migration[6.0]
def change
add_column :zoom_users, :account_number, :string
add_column :zoom_users, :tier, :integer, default: 0
end
end

View File

@@ -1,5 +0,0 @@
class AddFilmingHoursToLocationReleases < ActiveRecord::Migration[6.0]
def change
add_column :location_releases, :filming_hours, :text
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

@@ -50,7 +50,7 @@ $_$;
SET default_tablespace = '';
SET default_table_access_method = heap;
SET default_with_oids = false;
--
-- Name: account_auths; Type: TABLE; Schema: public; Owner: -
@@ -615,15 +615,6 @@ CREATE SEQUENCE public.contract_templates_id_seq
ALTER SEQUENCE public.contract_templates_id_seq OWNED BY public.contract_templates.id;
--
-- Name: data_migrations; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.data_migrations (
version character varying NOT NULL
);
--
-- Name: directories; Type: TABLE; Schema: public; Owner: -
--
@@ -1181,6 +1172,7 @@ CREATE TABLE public.settings (
--
CREATE SEQUENCE public.settings_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1216,6 +1208,7 @@ CREATE TABLE public.taggings (
--
CREATE SEQUENCE public.taggings_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1246,6 +1239,7 @@ CREATE TABLE public.tags (
--
CREATE SEQUENCE public.tags_id_seq
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -1326,6 +1320,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: -
--
@@ -1592,9 +1624,7 @@ CREATE TABLE public.zoom_users (
id bigint NOT NULL,
api_id character varying,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
account_number character varying,
tier integer DEFAULT 0
updated_at timestamp(6) without time zone NOT NULL
);
@@ -1834,6 +1864,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: -
--
@@ -2010,14 +2047,6 @@ ALTER TABLE ONLY public.contract_templates
ADD CONSTRAINT contract_templates_pkey PRIMARY KEY (id);
--
-- Name: data_migrations data_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.data_migrations
ADD CONSTRAINT data_migrations_pkey PRIMARY KEY (version);
--
-- Name: directories directories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2162,6 +2191,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: -
--
@@ -2765,6 +2802,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: -
--
@@ -3502,6 +3546,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200428091105'),
('20200507110804'),
('20200512161738'),
('20200526113516');
('20200518200245'),
('20200519191908'),
('20200610143327');

View File

@@ -3,7 +3,6 @@ class ZoomGateway
class MeetingExpired < StandardError; end
class UserNotFound < StandardError; end
class TooManyHosts < StandardError; end
class UserAlreadyExists < StandardError; end
class << self
def USER_TYPE_NAME
@@ -24,14 +23,6 @@ class ZoomGateway
"#{self.USER_TYPE_NAME}-directme-host"
end
def ACCOUNT_NUMBER
ENV['ZOOM_ACCOUNT_NUMBER']
end
def enable_recordings?
ENV['ZOOM_ENABLE_RECORDINGS'] == 'true'
end
def apply_limits?
self.USER_TYPE_NAME == 'pro'
end
@@ -42,14 +33,12 @@ class ZoomGateway
end
def create_meeting(host_id, **kwargs)
recording_type = self.class.enable_recordings? ? 'cloud' : 'none'
meeting = @client.meeting_create({ user_id: host_id,
topic: kwargs[:topic],
type: 1, # Instant meeting
settings: {
host_video: true,
participant_video: true,
auto_recording: recording_type,
participant_video: true
} })
meeting["id"]
end
@@ -89,10 +78,6 @@ class ZoomGateway
@client.user_delete(id: host_id)
end
def delete_recording(meeting_id, recording_id)
@client.recording_delete(meeting_id: meeting_id, recording_id: recording_id)
end
private
def parse_zoom_error(error)
@@ -102,8 +87,6 @@ class ZoomGateway
raise UserNotFound, error.message
elsif error.status_code == 3001
raise MeetingExpired, error.message
elsif error.status_code == 1005
raise UserAlreadyExists, error.message
else
raise error
end

View File

@@ -50,21 +50,4 @@ RSpec.describe BroadcastsChannel, type: :channel do
})
end
end
describe ".broadcast_file_upload_updates" do
it 'broadcasts to the channel with the right data' do
broadcast = create(:broadcast, :with_stream, :with_files, skip_create_callback: true)
files_content = ApplicationController.render partial: "broadcasts/file", collection: broadcast.files
expect {
BroadcastsChannel.broadcast_file_upload_updates(broadcast, broadcast.files, "pagination_content")
}.to have_broadcasted_to(broadcast).with({
event: 'file_upload_update',
broadcast_token: broadcast.token,
files_content: files_content,
pagination_content: "pagination_content"
})
end
end
end

View File

@@ -24,20 +24,4 @@ RSpec.describe ProjectsChannel, type: :channel do
}.to have_broadcasted_to(project).with(event: "video_status_update", content: content)
end
end
describe ".conference_recording_ready" do
it "broadcasts to the project channel" do
recording_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "files", "video_file.mp4"), "video/mp4")
zoom_meeting = create(:zoom_meeting, project: project, recording: recording_file)
video_url = 'http://url.to.video/video.mp4'
allow(zoom_meeting.recording).to receive(:service_url).and_return(video_url)
expect {
ProjectsChannel.conference_recording_ready(project, zoom_meeting.recording)
}.to have_broadcasted_to(project).with { |data|
expect(data['content']).to include(video_url)
expect(data['event']).to eq('conference_recording_ready')
}
end
end
end

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

@@ -26,7 +26,8 @@ RSpec.describe AppearanceReleasesController, tye: :controller do
get :index, params: { project_id: project }
expect(response.body).to have_content "John Doe"
expect(response.body).to have_content "P: 5551234567E: jane.doe@test.com"
expect(response.body).to have_content "555-123-4567"
expect(response.body).to have_content "jane.doe@test.com"
expect(response.body).to have_content "Some notes here"
expect(response.body).to have_button "Import Release"
expect(response.body).to have_content "Manage"

View File

@@ -111,6 +111,17 @@ RSpec.describe BroadcastsController, type: :controller do
end
end
describe "#update" do
let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, project: project ) }
it "uploads files to broadcast" do
patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true
expect(broadcast.files.count).to eq(1)
expect(broadcast.files.first.filename).to eq("contract.pdf")
end
end
describe "#show" do
let(:broadcast) { create(:broadcast, project: project, name: "Another Broadcast") }
@@ -187,25 +198,6 @@ RSpec.describe BroadcastsController, type: :controller do
end
end
describe "#update" do
let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, project: project ) }
it "uploads files to broadcast" do
patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true
expect(broadcast.files.count).to eq(1)
expect(broadcast.files.first.filename).to eq("contract.pdf")
end
it "sends an update to the broadcasts channel" do
allow(BroadcastsChannel).to receive(:broadcast_file_upload_updates)
patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true
expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates)
end
end
describe "#destroy" do
let!(:broadcast_2) { create(:broadcast, :with_stream, skip_create_callback: true, project: project, name: "Another Broadcast") }

View File

@@ -56,16 +56,6 @@ RSpec.describe PasswordResetsController, type: :controller do
expect(response.body).to have_content("Password Reset")
expect(response.body).to have_selector("input[name='password_reset[password]']")
end
context "when reset token is invalid" do
it "redirects to the sign in page" do
get :edit, params: { id: "bad token" }
expect(response).to be_redirect
expect(response).to redirect_to(new_session_path)
expect(flash.notice).to be_present
end
end
end
describe "#update" do

View File

@@ -92,14 +92,6 @@ RSpec.describe Public::BroadcastsController, type: :controller do
expect(broadcast.files.count).to eq(1)
expect(broadcast.files.first.filename).to eq("contract.pdf")
end
it "sends an update to the broadcasts channel" do
allow(BroadcastsChannel).to receive(:broadcast_file_upload_updates)
patch :update, params: { token: broadcast.token, broadcast: file_params }, xhr: true
expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates)
end
end
after do

View File

@@ -0,0 +1,130 @@
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 content" 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 "responds with a redirect" do
post :create, params: { project_id: project.id, task_request: task_request_params }
expect(response).to be_redirect
expect(flash.notice).not_to be_nil
end
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
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
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

@@ -69,13 +69,6 @@ RSpec.describe ZoomNotificationsController, type: :controller do
expect(zoom_meeting.reload).to be_ended
end
it 'updates the recording when recording complete notification is received' do
expect {
post :create, params: recording_complete
}.to change { zoom_meeting.recording }
end
end
end
end

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 "10 days"
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

@@ -1,9 +1,5 @@
require 'zoom_gateway'
FactoryBot.define do
factory :zoom_user do
account_number ZoomGateway.ACCOUNT_NUMBER
trait ZoomGateway.USER_TYPE_NAME
trait :with_api_id do
api_id "api_user_id"
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_link 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 'No files attached'
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

@@ -5,13 +5,6 @@ feature "User managing acquired_media releases" do
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
context "when signed out" do
scenario "United States is default country" do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_acquired_media_release_path(project.account, project, contract_template)
expect(country_field_value).to eq "US"
end
scenario "creating a release", js: true do
contract_template = create(:contract_template, project: project)
@@ -26,7 +19,7 @@ feature "User managing acquired_media releases" do
click_button "I have read and agree to the above"
expect(AcquiredMediaRelease.last.categories).to include("Video Footage")
expect(AcquiredMediaRelease.last.categories).to include("Artwork")
expect(AcquiredMediaRelease.last.categories).to include("Still Photograph")
expect(page).to have_content("Your release was successfully submitted. Thank you.")
end
@@ -212,16 +205,12 @@ feature "User managing acquired_media releases" do
private
def country_field_value
find_field("acquired_media_release[person_address_country]").value
end
def acquired_media_name_field
"acquired_media_release[name]"
end
def acquired_media_category_fields
find(:css, "#acquired_media_release_categories_video_footage").set(true)
find(:css, "#acquired_media_release_categories_artwork").set(true)
find(:css, "#acquired_media_release_categories_still_photograph").set(true)
end

View File

@@ -46,17 +46,15 @@ feature "User managing broadcasts" do
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")
end
click_on "Files"
expect(page).to have_content("contract.pdf")
click_on "Previous Sessions"
expect(page).to have_content(recording.download_file_name)
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)
broadcasts = create_list(:broadcast, 4, :with_stream, project: project)
visit project_broadcasts_path(project)
click_checkboxes
@@ -66,16 +64,8 @@ feature "User managing broadcasts" do
expect(page).to have_content("Switch View")
click_on "Switch View"
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")
click_on "Broadcast 2"
expect(page).to have_content("contract.pdf")
end
expect(page).to have_link(broadcasts.first.name)
expect(page).to have_link(broadcasts.second.name)
end
end
end
@@ -87,7 +77,7 @@ feature "User managing broadcasts" do
end
def click_checkboxes
all('input[type="checkbox"]')[0].click
all('input[type="checkbox"]')[1].click
all('input[type="checkbox"]')[2].click
end
end

View File

@@ -5,13 +5,6 @@ feature "User managing location releases" do
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
context "when signed out" do
scenario "United States is default country" do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_location_release_path(project.account, project, contract_template)
expect(country_field_value).to eq "US"
end
scenario "creating a release", js: true do
contract_template = create(:contract_template, project: project)
@@ -24,7 +17,6 @@ feature "User managing location releases" do
fill_in person_phone_field, with: "555-555-5555"
fill_in person_email_field, with: "jane.doe@test.com"
fill_in person_address_street1_field, with: "100 Broadway"
fill_in filming_hours_field, with: "04:00 - 22:00"
draw_signature file_fixture("signature.png"), "location_release_signature_base64"
end
@@ -59,7 +51,6 @@ feature "User managing location releases" do
by "filling out the remaining information" do
fill_in_release_fields name: "Test Location Release"
fill_in filming_hours_field, with: "04:00 - 22:00"
click_button create_release_button
expect(page).to have_content(create_release_notice)
expect(page).to have_photo("location_photo.png")
@@ -145,7 +136,6 @@ feature "User managing location releases" do
:native,
project: project,
name: "Benny's Burritos",
filming_hours: "06:00 - 20:00",
tag_list: "Restaurant",
notes: [
build(:note,
@@ -182,8 +172,6 @@ feature "User managing location releases" do
expect(pdf_body).to have_content("Restaurant")
expect(pdf_body).to have_content photos_heading.upcase
expect(pdf_body).to have_content("location_photo.png")
expect(pdf_body).to have_content("Filming Hours")
expect(pdf_body).to have_content("06:00 - 20:00")
end
context "when the user is associate" do
@@ -202,10 +190,6 @@ feature "User managing location releases" do
private
def country_field_value
find_field("location_release[person_address_country]").value
end
def photos_heading(photos_count = 1)
t 'contracts.photos.heading', count: photos_count
end
@@ -238,10 +222,6 @@ feature "User managing location releases" do
"location_release[person_phone]"
end
def filming_hours_field
"location_release[filming_hours]"
end
def have_photo(filename, attr: "src")
have_selector("img[#{attr}*='#{filename}']")
end

View File

@@ -5,13 +5,6 @@ feature "User managing material releases" do
let(:project) { create(:project, members: current_user, account: current_user.primary_account) }
context "when signed out" do
scenario "United States is default country" do
contract_template = create(:contract_template, project: project)
visit new_account_project_contract_template_material_release_path(project.account, project, contract_template)
expect(country_field_value).to eq "US"
end
scenario "creating a release", js: true do
contract_template = create(:contract_template, project: project)
@@ -187,10 +180,6 @@ feature "User managing material releases" do
private
def country_field_value
find_field("material_release[person_address_country]").value
end
def photos_heading(photos_count = 1)
t 'contracts.photos.heading', count: photos_count
end

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