* merged
This commit is contained in:
commit
b780b4a462
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Settings><!--This file was automatically generated by Ruby plugin.
|
||||
You are allowed to:
|
||||
1. Remove rake task
|
||||
2. Add existing rake tasks
|
||||
To add existing rake tasks automatically delete this file and reload the project.
|
||||
--><RakeGroup description="" fullCmd="" taksId="rake" /></Settings>
|
||||
|
|
@ -71,6 +71,7 @@ gem 'rest-client'
|
|||
gem 'iso-639'
|
||||
gem 'rubyzip'
|
||||
gem 'sanitize'
|
||||
gem 'slim'
|
||||
|
||||
group :libv8 do
|
||||
gem 'libv8', "~> 3.11.8"
|
||||
|
|
|
|||
|
|
@ -14,27 +14,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
filter :updated_at
|
||||
|
||||
|
||||
form do |ff|
|
||||
ff.inputs "Details" do
|
||||
ff.input :email
|
||||
ff.input :admin
|
||||
ff.input :raw_password, :label => 'Password'
|
||||
ff.input :first_name
|
||||
ff.input :last_name
|
||||
ff.input :city
|
||||
ff.input :state
|
||||
ff.input :country
|
||||
ff.input :musician
|
||||
ff.input :can_invite
|
||||
ff.input :photo_url
|
||||
ff.input :session_settings
|
||||
end
|
||||
ff.inputs "Signup" do
|
||||
ff.input :email_template, :label => 'Welcome Email Template Name'
|
||||
ff.input :confirm_url, :label => 'Signup Confirm URL'
|
||||
end
|
||||
ff.actions
|
||||
end
|
||||
form :partial => "form"
|
||||
|
||||
show do |user|
|
||||
attributes_table do
|
||||
|
|
@ -53,8 +33,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
row :gender
|
||||
row :email_confirmed
|
||||
row :image do user.photo_url ? image_tag(user.photo_url) : '' end
|
||||
row :session_settings
|
||||
row :can_invite
|
||||
end
|
||||
active_admin_comments
|
||||
end
|
||||
|
|
@ -114,6 +92,30 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
# call `create!` to ensure that the rest of the action continues as normal
|
||||
create!
|
||||
end
|
||||
|
||||
def update
|
||||
|
||||
@user = resource
|
||||
@user.email = params[:jam_ruby_user][:email]
|
||||
@user.admin = params[:jam_ruby_user][:admin]
|
||||
@user.musician = params[:jam_ruby_user][:musician]
|
||||
@user.first_name = params[:jam_ruby_user][:first_name]
|
||||
@user.last_name = params[:jam_ruby_user][:last_name]
|
||||
@user.state = params[:jam_ruby_user][:state]
|
||||
@user.city = params[:jam_ruby_user][:city]
|
||||
|
||||
|
||||
if params[:jam_ruby_user][:show_frame_options].to_i == 1
|
||||
@user.mod_merge({User::MOD_GEAR => {User::MOD_GEAR_FRAME_OPTIONS => true}})
|
||||
else
|
||||
@user.delete_mod(User::MOD_GEAR, User::MOD_GEAR_FRAME_OPTIONS)
|
||||
end
|
||||
|
||||
@user.save!
|
||||
|
||||
redirect_to edit_admin_user_path(@user)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
ActiveAdmin.register JamRuby::JamTrackLicensor, :as => 'JamTrack Licensors' do
|
||||
|
||||
menu :label => 'JamTrack Licensors', :parent => 'JamTracks'
|
||||
|
||||
config.sort_order = 'name_asc'
|
||||
config.batch_actions = false
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
||||
|
||||
menu :label => 'JamTracks', :parent => 'JamTracks'
|
||||
|
||||
config.sort_order = 'name_asc'
|
||||
config.batch_actions = false
|
||||
|
||||
filter :genre
|
||||
filter :status, :as => :select, collection: JamRuby::JamTrack::STATUS
|
||||
|
||||
form :partial => 'form'
|
||||
|
||||
index do
|
||||
column :id
|
||||
column :name
|
||||
column :description
|
||||
column :bpm
|
||||
column :time_signature
|
||||
column :status
|
||||
column :recording_type
|
||||
column :original_artist
|
||||
column :songwriter
|
||||
column :publisher
|
||||
column :licensor
|
||||
column :pro
|
||||
column :genre
|
||||
column :sales_region
|
||||
column :price
|
||||
column :reproduction_royalty
|
||||
column :public_performance_royalty
|
||||
column :reproduction_royalty_amount
|
||||
column :licensor_royalty_amount
|
||||
column :pro_royalty_amount
|
||||
column :url
|
||||
column :created_at
|
||||
|
||||
column :jam_track_tracks do |jam_track|
|
||||
table_for jam_track.jam_track_tracks.order('position ASC') do
|
||||
column :id
|
||||
column :track_type
|
||||
column :instrument
|
||||
column :part
|
||||
column :track do |track|
|
||||
link_to 'Play', '#'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# default_actions # use this for all view/edit/delete links
|
||||
column "Actions" do |jam_track|
|
||||
links = ''.html_safe
|
||||
links << link_to("Show Tracks", '#', :class => "member_link view_link show_tracks")
|
||||
links << link_to("Update", edit_resource_path(jam_track), :class => "member_link edit_link")
|
||||
links
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
$(document).ready(function() {
|
||||
$("th.jam_track_tracks").css('display', 'none');
|
||||
$("td.jam_track_tracks").css('display', 'none');
|
||||
|
||||
$(".show_tracks").click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $rowJamTrack = $(this).parents('tr');
|
||||
var $jamTrackTracks = $($rowJamTrack).find("td.jam_track_tracks");
|
||||
|
||||
var count = $jamTrackTracks.find("table tbody tr").length;
|
||||
|
||||
if ($rowJamTrack.next().attr('id') == "jam_track_tracks_detail") {
|
||||
$(this).html("Show Tracks");
|
||||
$rowJamTrack.next().remove();
|
||||
}
|
||||
else {
|
||||
$(this).html('Hide Tracks');
|
||||
if (count == 0) {
|
||||
$rowJamTrack.after(
|
||||
$("<tr id=\"jam_track_tracks_detail\"></tr>").html(
|
||||
$("<td colspan=\"18\"></td>")
|
||||
).append(
|
||||
$("<td colspan=\"4\"></td>").html(
|
||||
"No Tracks"
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$rowJamTrack.after(
|
||||
$("<tr id=\"jam_track_tracks_detail\"></tr>").html(
|
||||
$("<td colspan=\"18\"></td>")
|
||||
).append(
|
||||
$("<td colspan=\"4\"></td>").html(
|
||||
$jamTrackTracks.html()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
= semantic_form_for([:admin, resource], :html => {:multipart => true}, :url => resource.new_record? ? admin_jam_tracks_path : "#{ENV['RAILS_RELATIVE_URL_ROOT']}/admin/jam_tracks/#{resource.id}") do |f|
|
||||
= f.semantic_errors *f.object.errors.keys
|
||||
= f.inputs name: 'JamTrack fields' do
|
||||
|
||||
= f.input :name
|
||||
= f.input :description
|
||||
= f.input :bpm
|
||||
= f.input :time_signature, collection: JamRuby::JamTrack::TIME_SIGNATURES
|
||||
= f.input :status, collection: JamRuby::JamTrack::STATUS
|
||||
= f.input :recording_type, collection: JamRuby::JamTrack::RECORDING_TYPE
|
||||
= f.input :original_artist
|
||||
= f.input :songwriter
|
||||
= f.input :publisher
|
||||
= f.input :licensor, collection: JamRuby::JamTrackLicensor.all
|
||||
= f.input :pro, collection: JamRuby::JamTrack::PRO
|
||||
= f.input :genre, collection: JamRuby::Genre.all
|
||||
= f.input :sales_region, collection: JamRuby::JamTrack::SALES_REGION
|
||||
= f.input :price
|
||||
= f.input :reproduction_royalty, :label => 'Reproduction Royalty'
|
||||
= f.input :public_performance_royalty, :label => 'Public Performance Royalty'
|
||||
= f.input :reproduction_royalty_amount
|
||||
= f.input :licensor_royalty_amount
|
||||
= f.input :pro_royalty_amount
|
||||
= f.input :url, :as => :file, :label => 'Audio File'
|
||||
|
||||
= f.semantic_fields_for :jam_track_tracks do |track|
|
||||
= render 'jam_track_track_fields', f: track
|
||||
.links
|
||||
= link_to_add_association 'Add Track', f, :jam_track_tracks, class: 'button', style: 'margin:20px;padding:10px 20px'
|
||||
|
||||
= f.actions
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
= f.inputs name: 'Track fields' do
|
||||
|
||||
%ol.nested-fields
|
||||
= f.input :track_type, :as => :select, collection: JamRuby::JamTrackTrack::TRACK_TYPE
|
||||
= f.input :instrument, collection: Instrument.all
|
||||
= f.input :part
|
||||
= f.input :position
|
||||
|
||||
- if f.object.new_record?
|
||||
%p{style: 'margin-left:10px'}
|
||||
%i before you can upload, you must select 'Update JamTrack'
|
||||
- else
|
||||
= f.input :url, :as => :file, :label => 'Track file'
|
||||
- unless f.object.nil? || f.object[:url].nil?
|
||||
.current_file_holder{style: 'margin-bottom:10px'}
|
||||
%a{href: f.object.sign_url(3600), style: 'padding:0 0 0 20px'} Download
|
||||
|
||||
= link_to_remove_association "Delete Track", f, class: 'button', style: 'margin-left:10px'
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
= semantic_form_for([:admin_users, resource], :url => resource.new_record? ? admin_users_path : "#{ENV['RAILS_RELATIVE_URL_ROOT']}/admin/users/#{resource.id}") do |f|
|
||||
= f.inputs "Details" do
|
||||
= f.input :email, label: 'Email'
|
||||
= f.input :admin
|
||||
= f.input :first_name
|
||||
= f.input :last_name
|
||||
= f.input :city
|
||||
= f.input :state
|
||||
= f.input :musician
|
||||
= f.inputs "Gear Mods" do
|
||||
= f.input :show_frame_options, as: :boolean
|
||||
= f.actions
|
||||
|
|
@ -134,5 +134,10 @@ module JamAdmin
|
|||
# recording upload/download configs
|
||||
config.max_track_upload_failures = 10
|
||||
config.max_track_part_upload_failures = 3
|
||||
|
||||
# Use Private API Keys to communicate with Recurly's API v2. See https://docs.recurly.com/api/basics/authentication to learn more.
|
||||
config.recurly_private_api_key = '7d623daabfc2434fa2a893bb008eb3e6'
|
||||
# Use Public Keys to identify your site when using Recurly.js. See https://docs.recurly.com/js/#include to learn more.
|
||||
config.recurly_public_api_key = 'sc-SZlO11shkeA1WMGuISLGg5'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -42,4 +42,9 @@ JamAdmin::Application.configure do
|
|||
config.twitter_app_secret = 'PfG1jAUMnyrimPcDooUVQaJrG1IuDjUyGg5KciOo'
|
||||
|
||||
config.redis_host = "localhost:6379:1" # go to another db to not cross pollute into dev/production redis dbs
|
||||
|
||||
# Use Private API Keys to communicate with Recurly's API v2. See https://docs.recurly.com/api/basics/authentication to learn more.
|
||||
config.recurly_private_api_key = '4631527f203b41848523125b3ae51341'
|
||||
# Use Public Keys to identify your site when using Recurly.js. See https://docs.recurly.com/js/#include to learn more.
|
||||
config.recurly_public_api_key = 'sc-s6G2OA80Rwyvsb1RmS3mAE'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
class JamRuby::User
|
||||
|
||||
EMAIL_TMPL_WELCOME = 'welcome_message'
|
||||
EMAIL_TMPL_WELCOME_BETA = 'welcome_betauser'
|
||||
EMAIL_TMPL_WELCOMES = [EMAIL_TMPL_WELCOME_BETA, EMAIL_TMPL_WELCOME]
|
||||
|
||||
CONFIRM_URL = "http://www.jamkazam.com/confirm" # we can't get request.host_with_port, so hard-code confirm url (with user override)
|
||||
|
||||
attr_accessible :admin, :raw_password, :musician, :can_invite, :photo_url, :session_settings, :confirm_url, :email_template # :invite_email
|
||||
|
||||
def raw_password
|
||||
|
|
@ -25,50 +19,12 @@
|
|||
end
|
||||
end
|
||||
|
||||
def confirm_url
|
||||
@signup_confirm_url ||= CONFIRM_URL
|
||||
end
|
||||
|
||||
def confirm_url= url
|
||||
@signup_confirm_url = url
|
||||
end
|
||||
|
||||
def email_template
|
||||
@signup_email_template ||= EMAIL_TMPL_WELCOME_BETA
|
||||
end
|
||||
|
||||
def email_template= tmpl
|
||||
@signup_email_template = tmpl
|
||||
end
|
||||
|
||||
def admin_user
|
||||
User.where(:email => self.email)[0]
|
||||
end
|
||||
|
||||
after_create do
|
||||
self.update_attribute(:signup_token, SecureRandom.urlsafe_base64)
|
||||
url = confirm_url
|
||||
url.chomp!('/')
|
||||
|
||||
# only supporting two welcome templates ATM
|
||||
if EMAIL_TMPL_WELCOMES.index(self.email_template).nil?
|
||||
self.email_template = EMAIL_TMPL_WELCOME
|
||||
end
|
||||
# UserMailer.send(self.email_template, self, "#{url}/#{self.signup_token}").deliver
|
||||
def show_frame_options
|
||||
self.get_gear_mod(MOD_GEAR_FRAME_OPTIONS)
|
||||
end
|
||||
|
||||
after_save do
|
||||
logger.debug("*** after_save: #{self.admin_changed?}")
|
||||
if self.admin_changed?
|
||||
if self.admin
|
||||
if self.admin_user.nil?
|
||||
au = User.create(:email => self.email)
|
||||
au.update_attribute(:encrypted_password, self.password_digest)
|
||||
end
|
||||
else
|
||||
self.admin_user.try(:destroy)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -205,4 +205,54 @@ FactoryGirl.define do
|
|||
latency_tester.save
|
||||
end
|
||||
end
|
||||
|
||||
factory :jam_track_licensor, :class => JamRuby::JamTrackLicensor do
|
||||
sequence(:name) { |n| "licensor-#{n}" }
|
||||
sequence(:description) { |n| "description-#{n}" }
|
||||
sequence(:attention) { |n| "attention-#{n}" }
|
||||
sequence(:address_line_1) { |n| "address1-#{n}" }
|
||||
sequence(:address_line_2) { |n| "address2-#{n}" }
|
||||
sequence(:city) { |n| "city-#{n}" }
|
||||
sequence(:state) { |n| "state-#{n}" }
|
||||
sequence(:zip_code) { |n| "zipcode-#{n}" }
|
||||
sequence(:contact) { |n| "contact-#{n}" }
|
||||
sequence(:email) { |n| "email-#{n}" }
|
||||
sequence(:phone) { |n| "phone-#{n}" }
|
||||
end
|
||||
|
||||
factory :jam_track, :class => JamRuby::JamTrack do
|
||||
sequence(:name) { |n| "jam-track-#{n}" }
|
||||
sequence(:description) { |n| "description-#{n}" }
|
||||
bpm 100.1
|
||||
time_signature '4/4'
|
||||
status 'Production'
|
||||
recording_type 'Cover'
|
||||
sequence(:original_artist) { |n| "original-artist-#{n}" }
|
||||
sequence(:songwriter) { |n| "songwriter-#{n}" }
|
||||
sequence(:publisher) { |n| "publisher-#{n}" }
|
||||
pro 'ASCAP'
|
||||
sales_region 'United States'
|
||||
price 1.99
|
||||
reproduction_royalty true
|
||||
public_performance_royalty true
|
||||
reproduction_royalty_amount 0.999
|
||||
licensor_royalty_amount 0.999
|
||||
pro_royalty_amount 0.999
|
||||
|
||||
genre JamRuby::Genre.first
|
||||
association :licensor, factory: :jam_track_licensor
|
||||
end
|
||||
|
||||
factory :jam_track_track, :class => JamRuby::JamTrackTrack do
|
||||
position 1
|
||||
part 'lead guitar'
|
||||
track_type 'Track'
|
||||
instrument JamRuby::Instrument.find('electric guitar')
|
||||
association :jam_track, factory: :jam_track
|
||||
end
|
||||
|
||||
factory :jam_track_right, :class => JamRuby::JamTrackRight do
|
||||
association :jam_track, factory: :jam_track
|
||||
association :user, factory: :user
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -226,3 +226,6 @@ add_session_create_type.sql
|
|||
user_syncs_and_quick_mix.sql
|
||||
user_syncs_fix_dup_tracks_2408.sql
|
||||
deletable_recordings.sql
|
||||
jam_tracks.sql
|
||||
shopping_carts.sql
|
||||
recurly.sql
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
CREATE TABLE jam_track_licensors (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
name VARCHAR NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
attention TEXT,
|
||||
address_line_1 VARCHAR,
|
||||
address_line_2 VARCHAR,
|
||||
city VARCHAR,
|
||||
state VARCHAR,
|
||||
zip_code VARCHAR,
|
||||
contact VARCHAR,
|
||||
email VARCHAR,
|
||||
phone VARCHAR,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE jam_tracks (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
name VARCHAR NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
bpm decimal,
|
||||
time_signature VARCHAR,
|
||||
status VARCHAR,
|
||||
recording_type VARCHAR,
|
||||
original_artist TEXT,
|
||||
songwriter TEXT,
|
||||
publisher TEXT,
|
||||
pro VARCHAR,
|
||||
sales_region VARCHAR,
|
||||
price decimal,
|
||||
reproduction_royalty BOOLEAN,
|
||||
public_performance_royalty BOOLEAN,
|
||||
reproduction_royalty_amount DECIMAL,
|
||||
licensor_royalty_amount DECIMAL,
|
||||
pro_royalty_amount DECIMAL,
|
||||
url VARCHAR,
|
||||
md5 VARCHAR,
|
||||
length BIGINT,
|
||||
licensor_id VARCHAR(64) REFERENCES jam_track_licensors (id) ON DELETE SET NULL,
|
||||
genre_id VARCHAR(64) REFERENCES genres (id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE jam_track_tracks (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
position INTEGER,
|
||||
track_type VARCHAR,
|
||||
jam_track_id VARCHAR(64) REFERENCES jam_tracks(id) ON DELETE CASCADE,
|
||||
instrument_id VARCHAR(64) REFERENCES instruments(id) ON DELETE SET NULL,
|
||||
part VARCHAR,
|
||||
url VARCHAR,
|
||||
md5 VARCHAR,
|
||||
length BIGINT,
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX jam_track_tracks_position_uniqkey ON jam_track_tracks (position, jam_track_id);
|
||||
|
||||
CREATE TABLE jam_track_rights (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL REFERENCES users(id),
|
||||
jam_track_id VARCHAR(64) NOT NULL REFERENCES jam_tracks(id)
|
||||
);
|
||||
|
||||
CREATE INDEX jam_tracks_rights_uniqkey ON jam_track_rights (user_id, jam_track_id);
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE users ADD COLUMN recurly_code VARCHAR(50) DEFAULT NULL;
|
||||
ALTER TABLE jam_tracks ADD COLUMN plan_code VARCHAR(50) DEFAULT NULL;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE shopping_carts (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
quantity INTEGER NOT NULL DEFAULT 1,
|
||||
user_id VARCHAR(64) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
cart_id VARCHAR(64) NOT NULL,
|
||||
cart_class_name VARCHAR(64),
|
||||
cart_type VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
|
@ -72,6 +72,8 @@ require "jam_ruby/app/uploaders/perf_data_uploader"
|
|||
require "jam_ruby/app/uploaders/recorded_track_uploader"
|
||||
require "jam_ruby/app/uploaders/mix_uploader"
|
||||
require "jam_ruby/app/uploaders/music_notation_uploader"
|
||||
require "jam_ruby/app/uploaders/jam_track_uploader"
|
||||
require "jam_ruby/app/uploaders/jam_track_track_uploader"
|
||||
require "jam_ruby/app/uploaders/max_mind_release_uploader"
|
||||
require "jam_ruby/lib/desk_multipass"
|
||||
require "jam_ruby/lib/ip"
|
||||
|
|
@ -171,11 +173,16 @@ require "jam_ruby/models/email_batch_new_musician"
|
|||
require "jam_ruby/models/email_batch_progression"
|
||||
require "jam_ruby/models/email_batch_scheduled_sessions"
|
||||
require "jam_ruby/models/email_batch_set"
|
||||
require "jam_ruby/models/jam_track_licensor"
|
||||
require "jam_ruby/models/jam_track"
|
||||
require "jam_ruby/models/jam_track_track"
|
||||
require "jam_ruby/models/jam_track_right"
|
||||
require "jam_ruby/app/mailers/async_mailer"
|
||||
require "jam_ruby/app/mailers/batch_mailer"
|
||||
require "jam_ruby/app/mailers/progress_mailer"
|
||||
require "jam_ruby/models/affiliate_partner"
|
||||
require "jam_ruby/models/chat_message"
|
||||
require "jam_ruby/models/shopping_cart"
|
||||
require "jam_ruby/models/generic_state"
|
||||
require "jam_ruby/models/score_history"
|
||||
require "jam_ruby/models/jam_company"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
class JamTrackTrackUploader < CarrierWave::Uploader::Base
|
||||
# include CarrierWaveDirect::Uploader
|
||||
include CarrierWave::MimeTypes
|
||||
|
||||
process :set_content_type
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
JamRuby::UploaderConfiguration.set_aws_private_configuration(self)
|
||||
end
|
||||
|
||||
# Add a white list of extensions which are allowed to be uploaded.
|
||||
def extension_white_list
|
||||
%w(ogg)
|
||||
end
|
||||
|
||||
def store_dir
|
||||
nil
|
||||
end
|
||||
|
||||
def md5
|
||||
@md5 ||= ::Digest::MD5.file(current_path).hexdigest
|
||||
end
|
||||
|
||||
def filename
|
||||
"#{model.store_dir}/#{model.filename}" if model.id
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
class JamTrackUploader < CarrierWave::Uploader::Base
|
||||
# include CarrierWaveDirect::Uploader
|
||||
include CarrierWave::MimeTypes
|
||||
|
||||
process :set_content_type
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
JamRuby::UploaderConfiguration.set_aws_private_configuration(self)
|
||||
end
|
||||
|
||||
# Add a white list of extensions which are allowed to be uploaded.
|
||||
def extension_white_list
|
||||
%w(jka)
|
||||
end
|
||||
|
||||
def store_dir
|
||||
nil
|
||||
end
|
||||
|
||||
def md5
|
||||
@md5 ||= ::Digest::MD5.file(current_path).hexdigest
|
||||
end
|
||||
|
||||
def filename
|
||||
"#{model.store_dir}/#{model.filename}" if model.id
|
||||
end
|
||||
end
|
||||
|
|
@ -40,6 +40,11 @@ module ValidationMessages
|
|||
EMAIL_MATCHES_CURRENT = "is same as your current email"
|
||||
INVALID_FPFILE = "is not valid"
|
||||
|
||||
# recurly
|
||||
RECURLY_ERROR = "Error occurred during Recurly transaction."
|
||||
RECURLY_ACCOUNT_ERROR = "You don't have Recurly account yet."
|
||||
RECURLY_PARAMETER_ERROR = "You didn't input correct information for Recurly transaction."
|
||||
|
||||
#connection
|
||||
USER_OR_LATENCY_TESTER_PRESENT = "user or latency_tester must be present"
|
||||
SELECT_AT_LEAST_ONE = "Please select at least one track" # DO NOT CHANGE THIS TEXT MESSAGE UNLESS YOU CHANGE createSession.js.erb, which is looking for it
|
||||
|
|
@ -80,7 +85,7 @@ module ValidationMessages
|
|||
DIFFERENT_SOURCE_TARGET = 'can\'t be same as the sender'
|
||||
|
||||
# mods
|
||||
MODS_NO_SHOW_MUST_BE_HASH = 'no_show must be a hash'
|
||||
MODS_MUST_BE_HASH = 'must be a hash'
|
||||
MODS_UNKNOWN_KEY = 'unknown mod'
|
||||
|
||||
# takes either a string/string hash, or a string/array-of-strings|symbols hash,
|
||||
|
|
|
|||
|
|
@ -88,6 +88,14 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def exists?(filename)
|
||||
s3_bucket.objects[filename].exists?
|
||||
end
|
||||
|
||||
def length(filename)
|
||||
s3_bucket.objects[filename].content_length
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def s3_bucket
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ module JamRuby
|
|||
# genres
|
||||
has_and_belongs_to_many :recordings, :class_name => "JamRuby::Recording", :join_table => "recordings_genres"
|
||||
|
||||
# jam tracks
|
||||
has_many :jam_tracks, :class_name => "JamRuby::JamTrack"
|
||||
|
||||
def to_s
|
||||
description
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
module JamRuby
|
||||
class JamTrack < ActiveRecord::Base
|
||||
include JamRuby::S3ManagerMixin
|
||||
|
||||
TIME_SIGNATURES = %w{4/4 3/4 2/4 6/8 5/8'}
|
||||
STATUS = %w{Staging Production Retired}
|
||||
RECORDING_TYPE = %w{Cover Original}
|
||||
PRO = %w{ASCAP BMI SESAC}
|
||||
SALES_REGION = ['United States', 'Worldwide']
|
||||
|
||||
PRODUCT_TYPE = 'JamTrack'
|
||||
|
||||
mount_uploader :url, JamTrackUploader
|
||||
|
||||
attr_accessible :name, :description, :bpm, :time_signature, :status, :recording_type,
|
||||
:original_artist, :songwriter, :publisher, :licensor, :licensor_id, :pro, :genre, :genre_id, :sales_region, :price,
|
||||
:reproduction_royalty, :public_performance_royalty, :reproduction_royalty_amount,
|
||||
:licensor_royalty_amount, :pro_royalty_amount, :jam_track_tracks_attributes, as: :admin
|
||||
|
||||
validates :name, presence: true, uniqueness: true, length: {maximum: 200}
|
||||
validates :description, length: {maximum: 1000}
|
||||
validates_format_of :bpm, with: /^\d+\.*\d{0,1}$/
|
||||
validates :time_signature, inclusion: {in: [nil] + TIME_SIGNATURES}
|
||||
validates :status, inclusion: {in: [nil] + STATUS}
|
||||
validates :recording_type, inclusion: {in: [nil] + RECORDING_TYPE}
|
||||
validates :original_artist, length: {maximum: 200}
|
||||
validates :songwriter, length: {maximum: 1000}
|
||||
validates :publisher, length: {maximum: 1000}
|
||||
validates :pro, inclusion: {in: [nil] + PRO}
|
||||
validates :sales_region, inclusion: {in: [nil] + SALES_REGION}
|
||||
validates_format_of :price, with: /^\d+\.*\d{0,2}$/
|
||||
|
||||
validates :reproduction_royalty, inclusion: {in: [nil, true, false]}
|
||||
validates :public_performance_royalty, inclusion: {in: [nil, true, false]}
|
||||
validates_format_of :reproduction_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
validates_format_of :licensor_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
validates_format_of :pro_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
|
||||
before_save :sanitize_active_admin
|
||||
|
||||
belongs_to :genre, class_name: "JamRuby::Genre"
|
||||
belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id'
|
||||
|
||||
has_many :jam_track_tracks, :class_name => "JamRuby::JamTrackTrack", order: 'position ASC'
|
||||
|
||||
has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight", inverse_of: 'jam_track', :foreign_key => "jam_track_id"
|
||||
has_many :owners, :through => :jam_track_rights, :class_name => "JamRuby::User", :source => :user
|
||||
|
||||
accepts_nested_attributes_for :jam_track_tracks, allow_destroy: true
|
||||
|
||||
# create storage directory that will house this jam_track, as well as
|
||||
def store_dir
|
||||
"jam_tracks/#{created_at.strftime('%m-%d-%Y')}/#{id}"
|
||||
end
|
||||
|
||||
# create name of the file
|
||||
def filename
|
||||
"#{name}.jka"
|
||||
end
|
||||
|
||||
# creates a short-lived URL that has access to the object.
|
||||
# the idea is that this is used when a user who has the rights to this tries to download this JamTrack
|
||||
# we would verify their rights (can_download?), and generates a URL in response to the click so that they can download
|
||||
# but the url is short lived enough so that it wouldn't be easily shared
|
||||
def sign_url(expiration_time = 120)
|
||||
s3_manager.sign_url(self[:url], {:expires => expiration_time, :response_content_type => 'audio/jka', :secure => false})
|
||||
end
|
||||
|
||||
def can_download?(user)
|
||||
owners.include?(user)
|
||||
end
|
||||
|
||||
def self.index user, options = {}
|
||||
limit = options[:limit]
|
||||
limit ||= 20
|
||||
limit = limit.to_i
|
||||
|
||||
start = options[:start].presence
|
||||
start = start.to_i || 0
|
||||
|
||||
query = JamTrack.joins(:jam_track_tracks)
|
||||
.offset(start)
|
||||
.limit(limit)
|
||||
|
||||
query = query.where("jam_tracks.genre_id = '#{options[:genre]}'") unless options[:genre].blank?
|
||||
query = query.where("jam_track_tracks.instrument_id = '#{options[:instrument]}'") unless options[:instrument].blank?
|
||||
query = query.where("jam_tracks.sales_region = '#{options[:availability]}'") unless options[:availability].blank?
|
||||
query = query.group("jam_tracks.id")
|
||||
|
||||
if query.length == 0
|
||||
[query, nil]
|
||||
elsif query.length < limit
|
||||
[query, nil]
|
||||
else
|
||||
[query, start + limit]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sanitize_active_admin
|
||||
self.genre_id = nil if self.genre_id == ''
|
||||
self.licensor_id = nil if self.licensor_id == ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
module JamRuby
|
||||
class JamTrackLicensor < ActiveRecord::Base
|
||||
|
||||
attr_accessible :name, :description, :attention, :address_line_1, :address_line_2,
|
||||
:city, :state, :zip_code, :contact, :email, :phone, as: :admin
|
||||
|
||||
validates :name, presence: true, uniqueness: true, length: {maximum: 200}
|
||||
validates :description, length: {maximum: 1000}
|
||||
validates :attention, length: {maximum: 200}
|
||||
validates :address_line_1, length: {maximum: 200}
|
||||
validates :address_line_2, length: {maximum: 200}
|
||||
validates :city, length: {maximum: 200}
|
||||
validates :state, length: {maximum: 200}
|
||||
validates :zip_code, length: {maximum: 200}
|
||||
validates :contact, length: {maximum: 200}
|
||||
validates :email, length: {maximum: 200}
|
||||
validates :phone, length: {maximum: 200}
|
||||
|
||||
has_many :jam_tracks, :class_name => "JamRuby::JamTrack", foreign_key: 'licensor_id'
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
module JamRuby
|
||||
|
||||
# describes what users have rights to which tracks
|
||||
class JamTrackRight < ActiveRecord::Base
|
||||
|
||||
belongs_to :user, class_name: "JamRuby::User" # the owner, or purchaser of the jam_track
|
||||
belongs_to :jam_track, class_name: "JamRuby::JamTrack"
|
||||
|
||||
validates :user, presence:true
|
||||
validates :jam_track, presence:true
|
||||
|
||||
validates_uniqueness_of :user_id, scope: :jam_track_id
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
module JamRuby
|
||||
|
||||
# describes an audio track (like the drums, or guitar) that comprises a JamTrack
|
||||
class JamTrackTrack < ActiveRecord::Base
|
||||
include JamRuby::S3ManagerMixin
|
||||
|
||||
# there should only be one Master per JamTrack, but there can be N Track per JamTrack
|
||||
TRACK_TYPE = %w{Master Track}
|
||||
|
||||
mount_uploader :url, JamTrackTrackUploader
|
||||
|
||||
attr_accessible :track_type, :instrument, :instrument_id, :position, :part, :url, as: :admin
|
||||
|
||||
validates :position, presence: true, numericality: {only_integer: true}, length: {in: 1..1000}
|
||||
validates :part, length: {maximum: 20}
|
||||
validates :track_type, inclusion: {in: TRACK_TYPE }
|
||||
validates_uniqueness_of :position, scope: :jam_track_id
|
||||
validates_uniqueness_of :part, scope: :jam_track_id
|
||||
# validates :jam_track, presence: true
|
||||
|
||||
belongs_to :instrument, class_name: "JamRuby::Instrument"
|
||||
belongs_to :jam_track, class_name: "JamRuby::JamTrack"
|
||||
|
||||
# create storage directory that will house this jam_track, as well as
|
||||
def store_dir
|
||||
"#{jam_track.store_dir}/tracks"
|
||||
end
|
||||
|
||||
# create name of the file
|
||||
def filename
|
||||
track_type == 'Master' ? 'master.ogg' : "#{part}.ogg"
|
||||
end
|
||||
|
||||
# creates a short-lived URL that has access to the object.
|
||||
# the idea is that this is used when a user who has the rights to this tries to download this JamTrack
|
||||
# we would verify their rights (can_download?), and generates a URL in response to the click so that they can download
|
||||
# but the url is short lived enough so that it wouldn't be easily shared
|
||||
def sign_url(expiration_time = 120)
|
||||
s3_manager.sign_url(self[:url], {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false})
|
||||
end
|
||||
|
||||
def can_download?(user)
|
||||
# I think we have to make a special case for 'previews', but maybe that's just up to the controller to not check can_download?
|
||||
jam_track.owners.include?(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -68,7 +68,6 @@ module JamRuby
|
|||
validate :validate_timezone
|
||||
|
||||
before_create :generate_share_token
|
||||
before_create :add_to_feed
|
||||
#before_save :update_scheduled_start
|
||||
before_save :check_scheduling_info_changed
|
||||
|
||||
|
|
@ -81,12 +80,6 @@ module JamRuby
|
|||
true
|
||||
end
|
||||
|
||||
def add_to_feed
|
||||
feed = Feed.new
|
||||
feed.music_session = self
|
||||
end
|
||||
|
||||
|
||||
def update_scheduled_start
|
||||
|
||||
# it's very important that this only run if timezone changes, or scheduled_start changes
|
||||
|
|
@ -625,12 +618,6 @@ module JamRuby
|
|||
|
||||
hist.end_history if hist
|
||||
|
||||
feed = Feed.find_by_music_session_id(session_id)
|
||||
unless feed.nil?
|
||||
feed.active = false
|
||||
feed.save
|
||||
end
|
||||
|
||||
Notification.send_session_ended(session_id)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ module JamRuby
|
|||
attr_writer :is_skip_mount_uploader
|
||||
|
||||
attr_accessible :discard, :user, :user_id, :instrument_id, :sound, :client_id, :track_id, :client_track_id, :url, as: :admin
|
||||
|
||||
attr_writer :current_user
|
||||
|
||||
SOUND = %w(mono stereo)
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ module JamRuby
|
|||
PARAM_MUSICIAN = :srch_m
|
||||
PARAM_BAND = :srch_b
|
||||
PARAM_FEED = :srch_f
|
||||
PARAM_JAMTRACK = :srch_j
|
||||
|
||||
F_PER_PAGE = B_PER_PAGE = M_PER_PAGE = 20
|
||||
M_MILES_DEFAULT = 500
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
module JamRuby
|
||||
class ShoppingCart < ActiveRecord::Base
|
||||
|
||||
attr_accessible :quantity, :cart_type, :product_info
|
||||
|
||||
belongs_to :user, :inverse_of => :shopping_carts, :class_name => "JamRuby::User", :foreign_key => "user_id"
|
||||
|
||||
validates :cart_id, presence: true
|
||||
validates :cart_type, presence: true
|
||||
validates :cart_class_name, presence: true
|
||||
|
||||
default_scope order('created_at DESC')
|
||||
|
||||
def product_info
|
||||
product = self.cart_product
|
||||
{name: product.name, price: product.price} unless product.nil?
|
||||
end
|
||||
|
||||
def cart_product
|
||||
self.cart_class_name.classify.constantize.find_by_id self.cart_id unless self.cart_class_name.blank?
|
||||
end
|
||||
|
||||
def self.create user, product, quantity = 1
|
||||
cart = ShoppingCart.new
|
||||
cart.user = user
|
||||
cart.cart_type = product.class::PRODUCT_TYPE
|
||||
cart.cart_class_name = product.class.name
|
||||
cart.cart_id = product.id
|
||||
cart.quantity = quantity
|
||||
cart.save
|
||||
cart
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -19,6 +19,12 @@ module JamRuby
|
|||
JAM_REASON_IMPORT = 'i'
|
||||
JAM_REASON_LOGIN = 'l'
|
||||
|
||||
# MOD KEYS
|
||||
MOD_GEAR = "gear"
|
||||
MOD_GEAR_FRAME_OPTIONS = "show_frame_options"
|
||||
|
||||
MOD_NO_SHOW = "no_show"
|
||||
|
||||
devise :database_authenticatable, :recoverable, :rememberable
|
||||
|
||||
acts_as_mappable
|
||||
|
|
@ -121,6 +127,13 @@ module JamRuby
|
|||
# diagnostics
|
||||
has_many :diagnostics, :class_name => "JamRuby::Diagnostic"
|
||||
|
||||
# jam_tracks
|
||||
has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight", :foreign_key => "user_id"
|
||||
has_many :purchased_jam_tracks, :through => :jam_track_rights, :class_name => "JamRuby::JamTrack", :source => :jam_track, :order => :created_at
|
||||
|
||||
# Shopping carts
|
||||
has_many :shopping_carts, :class_name => "JamRuby::ShoppingCart"
|
||||
|
||||
# score history
|
||||
has_many :from_score_histories, :class_name => "JamRuby::ScoreHistory", foreign_key: 'from_user_id'
|
||||
has_many :to_score_histories, :class_name => "JamRuby::ScoreHistory", foreign_key: 'to_user_id'
|
||||
|
|
@ -189,8 +202,8 @@ module JamRuby
|
|||
# let's work to stop junk from getting into the mods array; this is essentially the schema
|
||||
def validate_mods
|
||||
mods_json.each do |key, value|
|
||||
if key == "no_show"
|
||||
errors.add(:mods, ValidationMessages::MODS_NO_SHOW_MUST_BE_HASH) unless value.is_a?(Hash)
|
||||
if key == MOD_NO_SHOW || key == MOD_GEAR
|
||||
errors.add(:mods, ValidationMessages::MODS_MUST_BE_HASH) unless value.is_a?(Hash)
|
||||
else
|
||||
errors.add(:mods, ValidationMessages::MODS_UNKNOWN_KEY)
|
||||
end
|
||||
|
|
@ -373,14 +386,52 @@ module JamRuby
|
|||
# new_modes should be a regular hash with non-symbolized keys (vs symbolized keys)
|
||||
def mod_merge(new_mods)
|
||||
self.mods = (mods_json.merge(new_mods) do |key, old_val, new_val|
|
||||
<<<<<<< HEAD
|
||||
if key == "no_show"
|
||||
# we take the values from previous no_shows, and merge it with the new no_shows
|
||||
=======
|
||||
if key == MOD_NO_SHOW || key == MOD_GEAR
|
||||
# we take the values from previous hash, and merge it with the new hash
|
||||
>>>>>>> develop
|
||||
old_val.merge(new_val)
|
||||
else
|
||||
raise "unknown in mode_merge key: #{key}"
|
||||
end
|
||||
end).to_json
|
||||
@mods_json = nil # invalidate this since we've updated self.mods
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
end
|
||||
|
||||
# any mod with the value 'null' will be deleted
|
||||
def delete_mod(root_key, sub_key)
|
||||
mod = mods_json
|
||||
root = mod[root_key]
|
||||
if root
|
||||
root.delete(sub_key)
|
||||
# check if root key is completely empty
|
||||
mod.delete(root_key) if root.length == 0
|
||||
# check if mod key is empty
|
||||
mod = nil if mod.length == 0
|
||||
end
|
||||
|
||||
self.mods = mod.nil? ? nil : mod.to_json
|
||||
@mods_json = nil # invalidate this since we've updated self.mods
|
||||
end
|
||||
|
||||
def get_mod(root_key, sub_key)
|
||||
mod = mods_json
|
||||
root = mod[root_key]
|
||||
root[sub_key] if root
|
||||
end
|
||||
|
||||
def get_gear_mod(sub_key)
|
||||
get_mod(MOD_GEAR, sub_key)
|
||||
end
|
||||
|
||||
def get_no_show_mod(sub_key)
|
||||
get_mod(MOD_NO_SHOW, sub_key)
|
||||
>>>>>>> develop
|
||||
end
|
||||
|
||||
def heartbeat_interval_client
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
|
||||
def run # if we haven't seen updated_at be tickled in 5 minutes, but config_changed is still set to TRUE, this record has gotten stale
|
||||
def run # if we have seen that sourced_needs_changing_at is older than 15 seconds ago, re-poke clients in the session
|
||||
IcecastMount.find_each(lock: true, :conditions => "sourced_needs_changing_at < (NOW() - interval '#{APP_CONFIG.icecast_max_sourced_changed} second')", :batch_size => 100) do |mount|
|
||||
if mount.music_session_id
|
||||
mount.with_lock do
|
||||
|
|
|
|||
|
|
@ -673,4 +673,54 @@ FactoryGirl.define do
|
|||
factory :max_mind_release, :class => JamRuby::MaxMindRelease do
|
||||
released_at Time.now.to_date
|
||||
end
|
||||
|
||||
factory :jam_track_licensor, :class => JamRuby::JamTrackLicensor do
|
||||
sequence(:name) { |n| "licensor-#{n}" }
|
||||
sequence(:description) { |n| "description-#{n}" }
|
||||
sequence(:attention) { |n| "attention-#{n}" }
|
||||
sequence(:address_line_1) { |n| "address1-#{n}" }
|
||||
sequence(:address_line_2) { |n| "address2-#{n}" }
|
||||
sequence(:city) { |n| "city-#{n}" }
|
||||
sequence(:state) { |n| "state-#{n}" }
|
||||
sequence(:zip_code) { |n| "zipcode-#{n}" }
|
||||
sequence(:contact) { |n| "contact-#{n}" }
|
||||
sequence(:email) { |n| "email-#{n}" }
|
||||
sequence(:phone) { |n| "phone-#{n}" }
|
||||
end
|
||||
|
||||
factory :jam_track, :class => JamRuby::JamTrack do
|
||||
sequence(:name) { |n| "jam-track-#{n}" }
|
||||
sequence(:description) { |n| "description-#{n}" }
|
||||
bpm 100.1
|
||||
time_signature '4/4'
|
||||
status 'Production'
|
||||
recording_type 'Cover'
|
||||
sequence(:original_artist) { |n| "original-artist-#{n}" }
|
||||
sequence(:songwriter) { |n| "songwriter-#{n}" }
|
||||
sequence(:publisher) { |n| "publisher-#{n}" }
|
||||
pro 'ASCAP'
|
||||
sales_region 'United States'
|
||||
price 1.99
|
||||
reproduction_royalty true
|
||||
public_performance_royalty true
|
||||
reproduction_royalty_amount 0.999
|
||||
licensor_royalty_amount 0.999
|
||||
pro_royalty_amount 0.999
|
||||
|
||||
genre JamRuby::Genre.first
|
||||
association :licensor, factory: :jam_track_licensor
|
||||
end
|
||||
|
||||
factory :jam_track_track, :class => JamRuby::JamTrackTrack do
|
||||
position 1
|
||||
part 'lead guitar'
|
||||
track_type 'Track'
|
||||
instrument JamRuby::Instrument.find('electric guitar')
|
||||
association :jam_track, factory: :jam_track
|
||||
end
|
||||
|
||||
factory :jam_track_right, :class => JamRuby::JamTrackRight do
|
||||
association :jam_track, factory: :jam_track
|
||||
association :user, factory: :user
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe JamTrackLicensor do
|
||||
|
||||
it "created" do
|
||||
FactoryGirl.create(:jam_track_licensor)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe JamTrackRight do
|
||||
|
||||
it "created" do
|
||||
jam_track_right = FactoryGirl.create(:jam_track_right)
|
||||
|
||||
user = jam_track_right.user
|
||||
jam_track = jam_track_right.jam_track
|
||||
|
||||
# verify that the user sees this as a purchased jam_track
|
||||
user.purchased_jam_tracks.should == [jam_track]
|
||||
|
||||
# verify that the jam_track sees the user as an owner
|
||||
jam_track.owners.should == [user]
|
||||
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it "one purchase per user/jam_track combo" do
|
||||
user = FactoryGirl.create(:user)
|
||||
jam_track = FactoryGirl.create(:jam_track)
|
||||
|
||||
right_1 = FactoryGirl.create(:jam_track_right, user: user, jam_track: jam_track)
|
||||
right_2 = FactoryGirl.build(:jam_track_right, user: user, jam_track: jam_track)
|
||||
right_2.valid?.should be_false
|
||||
right_2.errors[:user_id].should == ['has already been taken']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
require 'spec_helper'
|
||||
|
||||
require 'carrierwave/test/matchers'
|
||||
|
||||
describe JamTrack do
|
||||
include CarrierWave::Test::Matchers
|
||||
include UsesTempFiles
|
||||
|
||||
|
||||
it "created" do
|
||||
jam_track = FactoryGirl.create(:jam_track)
|
||||
jam_track.licensor.should_not be_nil
|
||||
jam_track.licensor.jam_tracks.should == [jam_track]
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
describe "bpm" do
|
||||
it "1" do
|
||||
FactoryGirl.build(:jam_track, bpm: 1).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100" do
|
||||
FactoryGirl.build(:jam_track, bpm: 100).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.1" do
|
||||
FactoryGirl.build(:jam_track, bpm: 100.1).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.12" do
|
||||
jam_track = FactoryGirl.build(:jam_track, bpm: 100.12)
|
||||
jam_track.valid?.should be_false
|
||||
jam_track.errors[:bpm].should == ['is invalid']
|
||||
end
|
||||
end
|
||||
|
||||
describe "price" do
|
||||
|
||||
it "0.99" do
|
||||
FactoryGirl.build(:jam_track, price: 0.99).valid?.should be_true
|
||||
end
|
||||
|
||||
it "1" do
|
||||
FactoryGirl.build(:jam_track, price: 1).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100" do
|
||||
FactoryGirl.build(:jam_track, price: 100).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.1" do
|
||||
FactoryGirl.build(:jam_track, price: 100.1).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.12" do
|
||||
FactoryGirl.build(:jam_track, price: 100.12).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.123" do
|
||||
jam_track = FactoryGirl.build(:jam_track, price: 100.123)
|
||||
jam_track.valid?.should be_false
|
||||
jam_track.errors[:price].should == ['is invalid']
|
||||
end
|
||||
end
|
||||
|
||||
describe "reproduction_royalty_amount" do
|
||||
it "0.99" do
|
||||
FactoryGirl.build(:jam_track, reproduction_royalty_amount: 0.99).valid?.should be_true
|
||||
end
|
||||
|
||||
it "1" do
|
||||
FactoryGirl.build(:jam_track, reproduction_royalty_amount: 1).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100" do
|
||||
FactoryGirl.build(:jam_track, reproduction_royalty_amount: 100).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.1" do
|
||||
FactoryGirl.build(:jam_track, reproduction_royalty_amount: 100.1).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.12" do
|
||||
FactoryGirl.build(:jam_track, reproduction_royalty_amount: 100.12).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.123" do
|
||||
FactoryGirl.build(:jam_track, reproduction_royalty_amount: 100.123).valid?.should be_true
|
||||
end
|
||||
|
||||
it "100.1234" do
|
||||
jam_track = FactoryGirl.build(:jam_track, reproduction_royalty_amount: 100.1234)
|
||||
jam_track.valid?.should be_false
|
||||
jam_track.errors[:reproduction_royalty_amount].should == ['is invalid']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "upload/download" do
|
||||
JKA_NAME = 'blah.jka'
|
||||
|
||||
in_directory_with_file(JKA_NAME)
|
||||
|
||||
before(:all) do
|
||||
original_storage = JamTrackUploader.storage = :fog
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
JamTrackUploader.storage = @original_storage
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
content_for_file('abc')
|
||||
end
|
||||
|
||||
it "uploads to s3 with correct name, and then downloads via signed URL" do
|
||||
jam_track = FactoryGirl.create(:jam_track)
|
||||
uploader = JamTrackUploader.new(jam_track, :url)
|
||||
uploader.store!(File.open(JKA_NAME)) # uploads file
|
||||
jam_track.save!
|
||||
|
||||
# verify that the uploader stores the correct path
|
||||
jam_track[:url].should == jam_track.store_dir + '/' + jam_track.filename
|
||||
|
||||
# verify it's on S3
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
s3.exists?(jam_track[:url]).should be_true
|
||||
s3.length(jam_track[:url]).should == 'abc'.length
|
||||
|
||||
# download it via signed URL, and check contents
|
||||
url = jam_track.sign_url
|
||||
downloaded_contents = open(url).read
|
||||
downloaded_contents.should == 'abc'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe JamTrackTrack do
|
||||
include CarrierWave::Test::Matchers
|
||||
include UsesTempFiles
|
||||
|
||||
it "created" do
|
||||
jam_track_track = FactoryGirl.create(:jam_track_track)
|
||||
jam_track_track.jam_track.should_not be_nil
|
||||
jam_track_track.jam_track.jam_track_tracks.should == [jam_track_track]
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it "position" do
|
||||
jam_track = FactoryGirl.create(:jam_track)
|
||||
jam_track_track_1 = FactoryGirl.create(:jam_track_track, position: 1, jam_track: jam_track)
|
||||
jam_track_track_2 = FactoryGirl.build(:jam_track_track, position: 1, jam_track: jam_track)
|
||||
jam_track_track_2.valid?.should == false
|
||||
jam_track_track_2.errors[:position].should == ['has already been taken']
|
||||
end
|
||||
|
||||
it "jam_track required" do
|
||||
pending "Need to be not mandatory because of activeadmin"
|
||||
jam_track = FactoryGirl.build(:jam_track_track, jam_track: nil)
|
||||
jam_track.valid?.should be_false
|
||||
jam_track.errors[:jam_track].should == ["can't be blank"]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "upload/download" do
|
||||
TRACK_NAME = 'lead guitar.ogg'
|
||||
|
||||
in_directory_with_file(TRACK_NAME)
|
||||
|
||||
before(:all) do
|
||||
original_storage = JamTrackTrackUploader.storage = :fog
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
JamTrackTrackUploader.storage = @original_storage
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
content_for_file('abc')
|
||||
end
|
||||
|
||||
it "uploads to s3 with correct name, and then downloads via signed URL" do
|
||||
jam_track_track = FactoryGirl.create(:jam_track_track)
|
||||
uploader = JamTrackTrackUploader.new(jam_track_track, :url)
|
||||
uploader.store!(File.open(TRACK_NAME)) # uploads file
|
||||
jam_track_track.save!
|
||||
|
||||
# verify that the uploader stores the correct path
|
||||
jam_track_track[:url].should == jam_track_track.store_dir + '/' + jam_track_track.filename
|
||||
|
||||
# verify it's on S3
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
s3.exists?(jam_track_track[:url]).should be_true
|
||||
s3.length(jam_track_track[:url]).should == 'abc'.length
|
||||
|
||||
# download it via signed URL, and check contents
|
||||
url = jam_track_track.sign_url
|
||||
downloaded_contents = open(url).read
|
||||
downloaded_contents.should == 'abc'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ShoppingCart do
|
||||
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
let(:jam_track) {FactoryGirl.create(:jam_track) }
|
||||
|
||||
before(:each) do
|
||||
ShoppingCart.delete_all
|
||||
end
|
||||
|
||||
it "can reference a shopping cart" do
|
||||
shopping_cart = ShoppingCart.create user, jam_track, 1
|
||||
|
||||
ShoppingCart.count.should == 1
|
||||
user.shopping_carts.count.should == 1
|
||||
user.shopping_carts[0].product_info[:name].should == jam_track.name
|
||||
user.shopping_carts[0].product_info[:price].should == jam_track.price
|
||||
user.shopping_carts[0].cart_type.should == jam_track.class::PRODUCT_TYPE
|
||||
user.shopping_carts[0].quantity.should == 1
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -608,7 +608,7 @@ describe User do
|
|||
it "does not allow non-hash no_show" do
|
||||
user.mod_merge({no_show:true})
|
||||
user.valid?.should be_false
|
||||
user.errors[:mods].should == [ValidationMessages::MODS_NO_SHOW_MUST_BE_HASH]
|
||||
user.errors[:mods].should == [ValidationMessages::MODS_MUST_BE_HASH]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ require 'fileutils'
|
|||
describe UnusedMusicNotationCleaner do
|
||||
include UsesTempFiles
|
||||
|
||||
NOTATION_TEMP_FILE='detail.png'
|
||||
UNUSED_NOTATION_TEMP_FILE='detail.png'
|
||||
|
||||
in_directory_with_file(NOTATION_TEMP_FILE)
|
||||
in_directory_with_file(UNUSED_NOTATION_TEMP_FILE)
|
||||
|
||||
before do
|
||||
content_for_file("this is music notation test file")
|
||||
|
|
@ -30,7 +30,8 @@ describe UnusedMusicNotationCleaner do
|
|||
|
||||
it "find no music notataions if music_session_id is nil and created at 1 hour ago" do
|
||||
notation = MusicNotation.new
|
||||
notation.file_url = File.open(NOTATION_TEMP_FILE)
|
||||
|
||||
notation.file_url = File.open(UNUSED_NOTATION_TEMP_FILE)
|
||||
notation.size = 10
|
||||
notation.user = FactoryGirl.create(:user)
|
||||
notation.created_at = Time.now - 1.hours
|
||||
|
|
@ -44,7 +45,7 @@ describe UnusedMusicNotationCleaner do
|
|||
music_session = FactoryGirl.create(:music_session, :session_removed_at => Time.now - 1.hours)
|
||||
|
||||
notation = MusicNotation.new
|
||||
notation.file_url = File.open(NOTATION_TEMP_FILE)
|
||||
notation.file_url = File.open(UNUSED_NOTATION_TEMP_FILE)
|
||||
notation.size = 10
|
||||
notation.user = FactoryGirl.create(:user)
|
||||
notation.created_at = Time.now - 1.hours
|
||||
|
|
@ -56,7 +57,7 @@ describe UnusedMusicNotationCleaner do
|
|||
|
||||
it "find music notataions if music_session_id is nil and created at 2 days ago" do
|
||||
notation = MusicNotation.new
|
||||
notation.file_url = File.open(NOTATION_TEMP_FILE)
|
||||
notation.file_url = File.open(UNUSED_NOTATION_TEMP_FILE)
|
||||
notation.size = 10
|
||||
notation.user = FactoryGirl.create(:user)
|
||||
notation.created_at = Time.now - 2.days
|
||||
|
|
@ -70,7 +71,7 @@ describe UnusedMusicNotationCleaner do
|
|||
music_session = FactoryGirl.create(:music_session, :session_removed_at => Time.now - 2.days)
|
||||
|
||||
notation = MusicNotation.new
|
||||
notation.file_url = File.open(NOTATION_TEMP_FILE)
|
||||
notation.file_url = File.open(UNUSED_NOTATION_TEMP_FILE)
|
||||
notation.size = 10
|
||||
notation.user = FactoryGirl.create(:user)
|
||||
notation.created_at = Time.now - 3.days
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ gem 'rubyzip'
|
|||
gem 'slim'
|
||||
gem 'htmlentities'
|
||||
gem 'sanitize'
|
||||
gem 'recurly'
|
||||
gem 'guard', '2.7.3'
|
||||
|
||||
group :development, :test do
|
||||
gem 'rspec-rails', '2.14.2'
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 779 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
|
|
@ -87,48 +87,54 @@
|
|||
var instrumentIds = $(e.target).attr('data-instrument-text');
|
||||
var params = buildRsvpRequestActionParams(rsvpId, true);
|
||||
|
||||
// first check if any open slots exist for these instruments
|
||||
rest.getOpenSessionSlots(sessionData.id, true)
|
||||
.done(function(openSlots) {
|
||||
if (openSlots) {
|
||||
if (openSlots.length === 0) {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName, function() {
|
||||
approve(rsvpId, params);
|
||||
});
|
||||
}
|
||||
else {
|
||||
var arrInstrumentIds = instrumentIds.split('|');
|
||||
var openSlotInstrumentIds = [];
|
||||
var unavailableSlotInstrumentIds = [];
|
||||
if (sessionData['is_unstructured_rsvp?']) {
|
||||
approve(rsvpId, params);
|
||||
}
|
||||
|
||||
// ensure each instrument in the user's list is available in the open slots list
|
||||
$.each(openSlots, function(index, slot) {
|
||||
openSlotInstrumentIds.push(slot.instrument_id);
|
||||
});
|
||||
|
||||
// build list of instrument IDs in the RSVP request for which there are no open slots
|
||||
for (var i=0; i < arrInstrumentIds.length; i++) {
|
||||
if ($.inArray(arrInstrumentIds[i], openSlotInstrumentIds) === -1) {
|
||||
unavailableSlotInstrumentIds.push(arrInstrumentIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (unavailableSlotInstrumentIds.length > 0) {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, unavailableSlotInstrumentIds, userName, function() {
|
||||
approve(rsvpId, params);
|
||||
});
|
||||
// check if any open slots exist for these instruments
|
||||
else {
|
||||
rest.getOpenSessionSlots(sessionData.id, true)
|
||||
.done(function(openSlots) {
|
||||
if (openSlots) {
|
||||
if (openSlots.length === 0) {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName, function() {
|
||||
approve(rsvpId, params);
|
||||
});
|
||||
}
|
||||
else {
|
||||
approve(rsvpId, params);
|
||||
var arrInstrumentIds = instrumentIds.split('|');
|
||||
var openSlotInstrumentIds = [];
|
||||
var unavailableSlotInstrumentIds = [];
|
||||
|
||||
// ensure each instrument in the user's list is available in the open slots list
|
||||
$.each(openSlots, function(index, slot) {
|
||||
openSlotInstrumentIds.push(slot.instrument_id);
|
||||
});
|
||||
|
||||
// build list of instrument IDs in the RSVP request for which there are no open slots
|
||||
for (var i=0; i < arrInstrumentIds.length; i++) {
|
||||
if ($.inArray(arrInstrumentIds[i], openSlotInstrumentIds) === -1) {
|
||||
unavailableSlotInstrumentIds.push(arrInstrumentIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (unavailableSlotInstrumentIds.length > 0) {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, unavailableSlotInstrumentIds, userName, function() {
|
||||
approve(rsvpId, params);
|
||||
});
|
||||
}
|
||||
else {
|
||||
approve(rsvpId, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName, function() {
|
||||
approve(rsvpId, params);
|
||||
});
|
||||
}
|
||||
});
|
||||
else {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName, function() {
|
||||
approve(rsvpId, params);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function approve(rsvpId, params) {
|
||||
|
|
@ -333,7 +339,7 @@
|
|||
|
||||
if ("instrument_list" in pending_rsvp_request && pending_rsvp_request.instrument_list != null) {
|
||||
$.each(pending_rsvp_request.instrument_list, function (index, instrument) {
|
||||
var instrumentId = instrument == null ? null : instrument.id;
|
||||
var instrumentId = context.JK.getInstrumentId(instrument.id);
|
||||
var inst = context.JK.getInstrumentIcon24(instrumentId);
|
||||
instrumentLogoHtml += '<img title="' + instrumentId + '" hoveraction="instrument" data-instrument-id="' + instrumentId + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentDesc.push(instrumentId);
|
||||
|
|
@ -372,7 +378,7 @@
|
|||
$.each(sessionData.approved_rsvps, function(index, approved_rsvp) {
|
||||
if ("instrument_list" in approved_rsvp) {
|
||||
$.each(approved_rsvp.instrument_list, function(index, instrument) {
|
||||
var instrumentId = instrument == null ? null : instrument.id;
|
||||
var instrumentId = context.JK.getInstrumentId(instrument.id);
|
||||
var inst = context.JK.getInstrumentIcon24(instrumentId);
|
||||
instrumentLogoHtml += '<img title="' + instrumentId + '" hoveraction="instrument" data-instrument-id="' + instrumentId + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
var nilOptionText = 'n/a';
|
||||
var bandId = '';
|
||||
var friendInput=null;
|
||||
var isSaving = false;
|
||||
|
||||
function is_new_record() {
|
||||
return bandId.length == 0;
|
||||
|
|
@ -126,16 +127,21 @@
|
|||
}
|
||||
|
||||
function saveBand() {
|
||||
if (isSaving) return;
|
||||
isSaving = true;
|
||||
|
||||
var band = buildBand()
|
||||
|
||||
if (is_new_record()) {
|
||||
rest.createBand(band)
|
||||
.done(function (response) {
|
||||
isSaving = false;
|
||||
createBandInvitations(response.id, function () {
|
||||
context.location = "/client#/bandProfile/" + response.id;
|
||||
});
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
isSaving = false;
|
||||
app.notifyServerError(jqXHR, "Unable to create band")
|
||||
});
|
||||
;
|
||||
|
|
@ -144,11 +150,13 @@
|
|||
band.id = bandId;
|
||||
rest.updateBand(band)
|
||||
.done(function (response) {
|
||||
isSaving = false;
|
||||
createBandInvitations(band.id, function () {
|
||||
context.location = "/client#/bandProfile/" + band.id;
|
||||
});
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
isSaving = false;
|
||||
app.notifyServerError(jqXHR, "Unable to create band")
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.CheckoutSignInScreen = function(app) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
|
||||
var $screen = null;
|
||||
var $navigation = null;
|
||||
var $signinForm = null;
|
||||
var $self = $(this);
|
||||
var $email = null;
|
||||
var $password = null;
|
||||
var $signinBtn = null;
|
||||
var $signupBtn = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
renderNavigation();
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function events() {
|
||||
$signinBtn.on('click', login);
|
||||
$signupBtn.on('click', signup);
|
||||
}
|
||||
|
||||
function signup(e) {
|
||||
app.layout.showDialog('signup-dialog');
|
||||
return false;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
$signinForm.removeClass('login-error');
|
||||
|
||||
$email.val('');
|
||||
$password.val('');
|
||||
}
|
||||
|
||||
function login() {
|
||||
var email = $email.val();
|
||||
var password = $password.val();
|
||||
|
||||
reset();
|
||||
|
||||
$signinBtn.text('TRYING...');
|
||||
|
||||
rest.login({email: email, password: password, remember_me: false})
|
||||
.done(function() {
|
||||
window.location = '/client#/order'
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
$signinForm.addClass('login-error')
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to log in")
|
||||
}
|
||||
})
|
||||
.always(function() {
|
||||
$signinBtn.text('SIGN IN')
|
||||
})
|
||||
}
|
||||
|
||||
function renderNavigation() {
|
||||
$navigation.html("");
|
||||
|
||||
var navigationHtml = $(
|
||||
context._.template(
|
||||
$('#template-checkout-navigation').html(),
|
||||
{current: 1},
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
|
||||
$navigation.append(navigationHtml);
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('signin', screenBindings);
|
||||
|
||||
$screen = $("#signInScreen");
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
$signinForm = $screen.find(".signin-form");
|
||||
$signinBtn = $signinForm.find('.signin-submit');
|
||||
$email = $signinForm.find('input[name="session[email]"]');
|
||||
$password = $signinForm.find('input[name="session[password]"]');
|
||||
$signupBtn = $signinForm.find('.show-signup-dialog');
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($navigation.length == 0) throw "$navigation must be specified";
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,274 @@
|
|||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.AdjustGearSpeedDialog = function (app) {
|
||||
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
|
||||
var gearUtils = context.JK.GearUtils;
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var $dialog = null;
|
||||
var modUtils = context.JK.ModUtils;
|
||||
|
||||
var $runTestBtn = null;
|
||||
var $scoreReport = null;
|
||||
var $speedOptions = null;
|
||||
var $saveBtn = null;
|
||||
var $cancelBtn = null;
|
||||
var $fairLabel = null;
|
||||
var $slowLabel = null;
|
||||
var $fastLabel = null;
|
||||
|
||||
var startingFramesize = null;
|
||||
var startingBufferIn = null;
|
||||
var startingBufferOut = null;
|
||||
|
||||
var frameBuffers = new context.JK.FrameBuffers(app);
|
||||
var gearTest = new context.JK.GearTest(app);
|
||||
|
||||
var selectedDeviceInfo;
|
||||
var deviceInformation;
|
||||
var operatingSystem;
|
||||
var frameBuffers;
|
||||
var $frameBuffers;
|
||||
var gearTest;
|
||||
|
||||
var $advanced;
|
||||
|
||||
function attemptScore() {
|
||||
gearTest.attemptScore(selectedDeviceInfo);
|
||||
}
|
||||
|
||||
function invalidateScore() {
|
||||
gearTest.invalidateScore();
|
||||
}
|
||||
|
||||
function getGearTest() {
|
||||
return gearTest;
|
||||
}
|
||||
|
||||
function updateDefaultBuffers() {
|
||||
gearUtils.updateDefaultBuffers(selectedDeviceInfo, frameBuffers)
|
||||
}
|
||||
|
||||
function onFramesizeChanged() {
|
||||
//context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
|
||||
updateDefaultBuffers();
|
||||
context.jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
|
||||
invalidateScore();
|
||||
}
|
||||
|
||||
function onBufferInChanged() {
|
||||
//context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
|
||||
context.jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
|
||||
invalidateScore();
|
||||
}
|
||||
|
||||
function onBufferOutChanged() {
|
||||
//context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
|
||||
context.jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
|
||||
invalidateScore();
|
||||
}
|
||||
|
||||
function freezeAudioInteraction() {
|
||||
logger.debug("adjustGearSpeed: freezing audio interaction");
|
||||
frameBuffers.disable();
|
||||
$speedOptions.iCheck('disable')
|
||||
$cancelBtn.on('click', false).addClass('disabled');
|
||||
$runTestBtn.on('click', false).addClass('disabled');
|
||||
}
|
||||
|
||||
function unfreezeAudioInteraction() {
|
||||
logger.debug("adjustGearSpeed: unfreezing audio interaction");
|
||||
frameBuffers.enable();
|
||||
$speedOptions.iCheck('enable')
|
||||
$cancelBtn.off('click', false).removeClass('disabled')
|
||||
$runTestBtn.off('click', false).removeClass('disabled')
|
||||
}
|
||||
|
||||
|
||||
function updateDefaultLabel() {
|
||||
if(selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm')) {
|
||||
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
|
||||
function translateFrameSizeToSpeed(framesize) {
|
||||
if(framesize == 2.5) {
|
||||
return 'fast'
|
||||
}
|
||||
else if(framesize == 5) {
|
||||
return 'fair'
|
||||
}
|
||||
else if (framesize == 10) {
|
||||
return "slow"
|
||||
}
|
||||
else {
|
||||
throw "unknown framesize in translateFrameSizeToSpeed: " + framesize
|
||||
}
|
||||
}
|
||||
|
||||
function beforeShow() {
|
||||
selectedDeviceInfo = gearUtils.selectedDeviceInfo(context.jamClient.FTUEGetInputMusicDevice(), context.jamClient.FTUEGetOutputMusicDevice());
|
||||
deviceInformation = gearUtils.loadDeviceInfo();
|
||||
startingFramesize = context.jamClient.FTUEGetFrameSize();
|
||||
startingBufferIn = context.jamClient.FTUEGetInputLatency();
|
||||
startingBufferOut = context.jamClient.FTUEGetOutputLatency();
|
||||
var startingSpeed = translateFrameSizeToSpeed(startingFramesize)
|
||||
logger.debug("speed upon entry: " + startingSpeed)
|
||||
$speedOptions.filter('[value=' + startingSpeed + ']').iCheck('check')
|
||||
setBuffers(startingSpeed);
|
||||
updateDefaultLabel();
|
||||
invalidateScore();
|
||||
$saveBtn.on('click', false).addClass('disabled');
|
||||
app.user().done(function() {
|
||||
if(modUtils.getGear('show_frame_options')) {
|
||||
$advanced.show();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
var scoring = gearTest.isScoring();
|
||||
|
||||
if(!scoring) {
|
||||
logger.debug("resetting framesize/buffers on cancel of adjust-gear-speed")
|
||||
// make sure the frame/buffer values are the same as when entered
|
||||
context.jamClient.FTUESetFrameSize(startingFramesize);
|
||||
context.jamClient.FTUESetInputLatency(startingBufferIn);
|
||||
context.jamClient.FTUESetOutputLatency(startingBufferOut);
|
||||
}
|
||||
|
||||
return !scoring;
|
||||
}
|
||||
|
||||
function onSave() {
|
||||
|
||||
if($(this).is('.disabled')) {
|
||||
logger.debug("cancelling save because not allowed yet")
|
||||
return;
|
||||
}
|
||||
|
||||
context.jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
|
||||
context.jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
|
||||
context.jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
|
||||
|
||||
app.layout.closeDialog('adjust-gear-speed-dialog')
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function onGearTestStarted(e, data) {
|
||||
renderScoringStarted();
|
||||
}
|
||||
|
||||
function onGearTestDone(e, data) {
|
||||
renderScoringStopped();
|
||||
$saveBtn.off('click', false).removeClass('disabled');
|
||||
gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
|
||||
}
|
||||
|
||||
function onGearTestFail(e, data) {
|
||||
renderScoringStopped();
|
||||
$saveBtn.on('click', false).addClass('disabled');
|
||||
gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
|
||||
}
|
||||
|
||||
function renderScoringStarted() {
|
||||
freezeAudioInteraction();
|
||||
}
|
||||
|
||||
function renderScoringStopped() {
|
||||
unfreezeAudioInteraction();
|
||||
}
|
||||
|
||||
function setBuffers(speed) {
|
||||
var newFrameSize = null;
|
||||
if(speed == 'fast') {
|
||||
newFrameSize = 2.5
|
||||
}
|
||||
else if (speed == 'fair') {
|
||||
newFrameSize = 5
|
||||
}
|
||||
else if (speed == 'slow') {
|
||||
newFrameSize = 10
|
||||
}
|
||||
else {
|
||||
throw "unknown speed setting: " + speed;
|
||||
}
|
||||
|
||||
frameBuffers.setFramesize(newFrameSize);
|
||||
jamClient.FTUESetFrameSize(newFrameSize);
|
||||
updateDefaultBuffers();
|
||||
}
|
||||
|
||||
function onSpeedChanged() {
|
||||
|
||||
setTimeout(function() {
|
||||
var speed = $dialog.find('.speed-option .iradio_minimal.checked input').val()
|
||||
|
||||
setBuffers(speed);
|
||||
|
||||
attemptScore();
|
||||
}, 1)
|
||||
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'beforeHide': beforeHide,
|
||||
'onCancel' : onCancel
|
||||
};
|
||||
|
||||
app.bindDialog('adjust-gear-speed-dialog', dialogBindings);
|
||||
|
||||
$dialog = $('#adjust-gear-speed-dialog');
|
||||
|
||||
$runTestBtn = $dialog.find('.run-test-btn');
|
||||
$scoreReport = $dialog.find('.results');
|
||||
$saveBtn = $dialog.find('.btnSave')
|
||||
$cancelBtn = $dialog.find('.btnCancel')
|
||||
$slowLabel = $dialog.find('label[for="adjust-gear-speed-slow"]')
|
||||
$fairLabel = $dialog.find('label[for="adjust-gear-speed-fair"]')
|
||||
$fastLabel = $dialog.find('label[for="adjust-gear-speed-fast"]')
|
||||
|
||||
operatingSystem = context.JK.GetOSAsString();
|
||||
|
||||
$frameBuffers = $dialog.find('.frame-and-buffers');
|
||||
frameBuffers.initialize($frameBuffers);
|
||||
$(frameBuffers)
|
||||
.on(frameBuffers.FRAMESIZE_CHANGED, onFramesizeChanged)
|
||||
.on(frameBuffers.BUFFER_IN_CHANGED, onBufferInChanged)
|
||||
.on(frameBuffers.BUFFER_OUT_CHANGED, onBufferOutChanged)
|
||||
|
||||
|
||||
gearTest.initialize($scoreReport, true)
|
||||
$(gearTest)
|
||||
.on(gearTest.GEAR_TEST_START, onGearTestStarted)
|
||||
.on(gearTest.GEAR_TEST_DONE, onGearTestDone)
|
||||
.on(gearTest.GEAR_TEST_FAIL, onGearTestFail)
|
||||
|
||||
$runTestBtn.click(attemptScore);
|
||||
|
||||
$dialog.data('result', gearTest); // so that others can peek into gear test data after dialog is closed
|
||||
|
||||
$advanced = $dialog.find('.advanced');
|
||||
$speedOptions = $dialog.find('.speed-option input');
|
||||
context.JK.checkbox($speedOptions).on('ifClicked', onSpeedChanged)
|
||||
|
||||
$saveBtn.click(onSave)
|
||||
};
|
||||
|
||||
|
||||
this.getGearTest = getGearTest;
|
||||
this.initialize = initialize;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window, jQuery);
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
}
|
||||
|
||||
hide();
|
||||
|
||||
|
||||
logger.debug("opening banner:" + options.title);
|
||||
|
||||
var $h1 = $banner.find('h1');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.JamtrackAvailabilityDialog = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var $dialog = null;
|
||||
var dialogId = 'jamtrack-availability-dialog';
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$dialog = $('[layout-id="' + dialogId + '"]');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
};
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
$('.session-name', $dialog).html(response.name);
|
||||
$('.scheduled-start', $dialog).html(response.pretty_scheduled_start_with_timezone);
|
||||
|
||||
if (response.recurring_mode !== null) {
|
||||
if (response.recurring_mode !== null && response.recurring_mode !== 'once') {
|
||||
$('.schedule-recurrence', $dialog).html("Recurs " + response.recurring_mode + " on this day at this time");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
$('.scheduled-start', $dialog).html(response.pretty_scheduled_start_with_timezone);
|
||||
|
||||
if (response.recurring_mode !== null && response.recurring_mode === 'weekly') {
|
||||
if (response.recurring_mode !== null && response.recurring_mode !== 'once') {
|
||||
$('.schedule-recurrence', $dialog).html("Recurs " + response.recurring_mode + " on this day at this time");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,6 +137,10 @@
|
|||
$controls.data('view-context', 'feed')
|
||||
$controls.addClass(mixInfo.mixStateClass)
|
||||
$status.text(mixInfo.mixStateMsg)
|
||||
|
||||
if(mixInfo.mixState == 'mixed' || mixInfo.mixState == 'stream-mix') {
|
||||
$controls.addClass('has-mix')
|
||||
}
|
||||
}
|
||||
|
||||
initialize();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
this.showBubble = function($hoverElement) {
|
||||
|
||||
rest.getBand(bandId)
|
||||
return rest.getBand(bandId)
|
||||
.done(function(response) {
|
||||
$(hoverSelector).html('');
|
||||
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
instrumentHtml = '<td><div class="nowrap">';
|
||||
if (val.instruments) { // @FIXME: edge case for Test user that has no instruments?
|
||||
$.each(val.instruments, function(index, instrument) {
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(instrument.instrument_id) + '" title="' + instrument.instrument_id + '" width="24" height="24" /> ';
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(instrument.instrument_id) + '" title="' + context.JK.getInstrumentId(instrument.instrument_id) + '" width="24" height="24" /> ';
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
this.showBubble = function($hoverElement) {
|
||||
|
||||
rest.getUserDetail({id: userId})
|
||||
return rest.getUserDetail({id: userId})
|
||||
.done(function(response) {
|
||||
$(hoverSelector).html('');
|
||||
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@
|
|||
this.showBubble = function($hoverElement) {
|
||||
$templateLatency = $("#template-account-session-latency");
|
||||
|
||||
rest.getUserDetail({id: userId})
|
||||
return rest.getUserDetail({id: userId})
|
||||
.done(function(response) {
|
||||
$(hoverSelector).html('');
|
||||
|
||||
// instruments
|
||||
var instrumentHtml = '';
|
||||
$.each(response.instruments, function(index, val) {
|
||||
instrumentHtml += '<div class="left mr10 mb"><img src="' + context.JK.getInstrumentIcon24(val.instrument_id) + '" title="' + val.instrument_id + '" width="24" height="24" /></div>';
|
||||
instrumentHtml += '<div class="left mr10 mb"><img src="' + context.JK.getInstrumentIcon24(val.instrument_id) + '" title="' + context.JK.getInstrumentId(val.instrument_id) + '" width="24" height="24" /></div>';
|
||||
});
|
||||
|
||||
// followings
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
|
||||
var latencyBadge = context._.template(
|
||||
$templateLatency.html(),
|
||||
$.extend(sessionUtils.createLatency(response), response),
|
||||
$.extend(response, sessionUtils.createLatency(response)),
|
||||
{variable: 'data'}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
this.showBubble = function($hoverElement) {
|
||||
|
||||
rest.getClaimedRecording(recordingId)
|
||||
return rest.getClaimedRecording(recordingId)
|
||||
.done(function(response) {
|
||||
var claimedRecording = response;
|
||||
var recording = response.recording;
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
instrumentHtml = '<td><div class="nowrap">';
|
||||
$.each(val.instrument_ids, function(index, val) {
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(val) + '" title="' + val + '" width="24" height="24" /> ';
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(val) + '" title="' + context.JK.getInstrumentId(val) + '" width="24" height="24" /> ';
|
||||
});
|
||||
instrumentHtml += '</div></td>';
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
this.showBubble = function($hoverElement) {
|
||||
|
||||
rest.getSessionHistory(sessionId)
|
||||
return rest.getSessionHistory(sessionId)
|
||||
.done(function(response) {
|
||||
$(hoverSelector).html('');
|
||||
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
instrumentHtml = '<td><div class="nowrap">';
|
||||
var instruments = val.instruments.split("|");
|
||||
$.each(instruments, function(index, instrument) {
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(instrument) + '" title="' + instrument + '" width="24" height="24" /> ';
|
||||
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(instrument) + '" title="' + context.JK.getInstrumentId(instrument) + '" width="24" height="24" /> ';
|
||||
});
|
||||
|
||||
instrumentHtml += '</div></td>';
|
||||
|
|
|
|||
|
|
@ -238,6 +238,10 @@
|
|||
}
|
||||
|
||||
function cancelRsvpRequest(sessionId, rsvpRequestId, cancelAll) {
|
||||
var cancel = "yes";
|
||||
if (cancelAll) {
|
||||
cancel = "all";
|
||||
}
|
||||
return $.ajax({
|
||||
url: '/api/rsvp_requests/' + rsvpRequestId,
|
||||
type: "DELETE",
|
||||
|
|
@ -939,7 +943,11 @@
|
|||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
url: "/api/users/progression/certified_gear",
|
||||
data: JSON.stringify(options)
|
||||
processData: false,
|
||||
data: JSON.stringify({
|
||||
success: options.success,
|
||||
reason: options.reason
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1257,6 +1265,98 @@
|
|||
});
|
||||
}
|
||||
|
||||
function updateAudioLatency(options) {
|
||||
var id = getId(options);
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/users/' + id + '/audio_latency',
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
data: options,
|
||||
});
|
||||
}
|
||||
|
||||
function getJamtracks(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/jamtracks?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function addJamtrackToShoppingCart(options) {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/shopping_carts/add_jamtrack?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'applications/json'
|
||||
});
|
||||
}
|
||||
|
||||
function getShoppingCarts() {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/shopping_carts',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function removeShoppingCart(options) {
|
||||
return $.ajax({
|
||||
type: "DELETE",
|
||||
url: '/api/shopping_carts?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
})
|
||||
}
|
||||
|
||||
function getRecurlyAccount() {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/recurly/get_account',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function createRecurlyAccount(options) {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/recurly/create_account?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function getBillingInfo() {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/recurly/billing_info',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function updateBillingInfo(options) {
|
||||
return $.ajax({
|
||||
type: "PUT",
|
||||
url: '/api/recurly/update_billing_info?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function placeOrder(options) {
|
||||
return $.ajax({
|
||||
type: "PUT",
|
||||
url: '/api/recurly/place_order?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function searchMusicians(query) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
|
|
@ -1375,6 +1475,16 @@
|
|||
this.getChatMessages = getChatMessages;
|
||||
this.createDiagnostic = createDiagnostic;
|
||||
this.getLatencyTester = getLatencyTester;
|
||||
this.updateAudioLatency = updateAudioLatency;
|
||||
this.getJamtracks = getJamtracks;
|
||||
this.addJamtrackToShoppingCart = addJamtrackToShoppingCart;
|
||||
this.getShoppingCarts = getShoppingCarts;
|
||||
this.removeShoppingCart = removeShoppingCart;
|
||||
this.getRecurlyAccount = getRecurlyAccount;
|
||||
this.createRecurlyAccount = createRecurlyAccount;
|
||||
this.getBillingInfo = getBillingInfo;
|
||||
this.updateBillingInfo = updateBillingInfo;
|
||||
this.placeOrder = placeOrder;
|
||||
this.searchMusicians = searchMusicians;
|
||||
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@
|
|||
var rest = context.JK.Rest();
|
||||
var inBadState = false;
|
||||
var userDeferred = null;
|
||||
|
||||
var userData = null;
|
||||
var self = this;
|
||||
|
||||
var opts = {
|
||||
inClient: true, // specify false if you want the app object but none of the client-oriented features
|
||||
|
|
@ -301,6 +302,7 @@
|
|||
logger.debug("updating user info")
|
||||
userDeferred = update; // update the global user object if this succeeded
|
||||
})
|
||||
update.done(this.updateUserCache)
|
||||
return update;
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +311,15 @@
|
|||
return userDeferred;
|
||||
}
|
||||
|
||||
// gets the most recent user data. can be null when app is still initializing.
|
||||
// user app.user() if initialize sequence is unknown/asynchronous
|
||||
this.currentUser = function() {
|
||||
if(userData == null) {
|
||||
throw "currentUser has null user data"
|
||||
}
|
||||
return userData;
|
||||
}
|
||||
|
||||
this.activeElementEvent = function(evtName, data) {
|
||||
return this.layout.activeElementEvent(evtName, data);
|
||||
}
|
||||
|
|
@ -333,6 +344,10 @@
|
|||
}
|
||||
};
|
||||
|
||||
this.updateUserCache = function(_userData) {
|
||||
userData = _userData
|
||||
}
|
||||
|
||||
this.initialize = function (inOpts) {
|
||||
var url, hash;
|
||||
app = this;
|
||||
|
|
@ -343,6 +358,7 @@
|
|||
this.layout.handleDialogState();
|
||||
|
||||
userDeferred = rest.getUserDetail();
|
||||
userDeferred.done(this.updateUserCache)
|
||||
|
||||
if (opts.inClient) {
|
||||
registerBadStateRecovered();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,259 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.JamTrackScreen = function(app) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
|
||||
var $screen = null;
|
||||
var $content = null;
|
||||
var $scroller = null;
|
||||
var $genre = null;
|
||||
var $instrument = null;
|
||||
var $availability = null;
|
||||
var $nextPager = null;
|
||||
var $noMoreJamtracks = null;
|
||||
|
||||
var currentQuery = defaultQuery();
|
||||
var currentPage = 0;
|
||||
var LIMIT = 10;
|
||||
var next = null;
|
||||
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
||||
|
||||
function beforeShow(data) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function events() {
|
||||
$genre.on("change", search);
|
||||
$instrument.on("change", search);
|
||||
$availability.on("change", search);
|
||||
}
|
||||
|
||||
function clearResults() {
|
||||
//logger.debug("CLEARING CONTENT")
|
||||
currentPage = 0;
|
||||
$content.empty();
|
||||
$noMoreJamtracks.hide();
|
||||
next = null;
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
currentQuery = buildQuery();
|
||||
rest.getJamtracks(currentQuery)
|
||||
.done(function(response) {
|
||||
clearResults();
|
||||
handleJamtrackResponse(response);
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
clearResults();
|
||||
$noMoreJamtracks.show();
|
||||
app.notifyServerError(jqXHR, 'Jamtrack Unavailable')
|
||||
})
|
||||
}
|
||||
|
||||
function search() {
|
||||
logger.debug("Searching for jamtracks...");
|
||||
refresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
function defaultQuery() {
|
||||
var query = { limit:LIMIT, page:currentPage};
|
||||
|
||||
if(next) {
|
||||
query.since = next;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
function buildQuery() {
|
||||
currentQuery = defaultQuery();
|
||||
|
||||
// genre filter
|
||||
var genres = $screen.find('#jamtrack_genre').val();
|
||||
if (genres !== undefined) {
|
||||
currentQuery.genre = genres;
|
||||
}
|
||||
|
||||
// instrument filter
|
||||
var instrument = $instrument.val();
|
||||
if (instrument !== undefined) {
|
||||
currentQuery.instrument = instrument;
|
||||
}
|
||||
|
||||
// availability filter
|
||||
var availability = $availability.val();
|
||||
if (availability !== undefined) {
|
||||
currentQuery.availability = availability;
|
||||
}
|
||||
|
||||
return currentQuery;
|
||||
}
|
||||
|
||||
function handleJamtrackResponse(response) {
|
||||
//logger.debug("Handling response", JSON.stringify(response))
|
||||
next = response.next;
|
||||
|
||||
renderJamtracks(response);
|
||||
|
||||
if(response.next == null) {
|
||||
// if we less results than asked for, end searching
|
||||
$scroller.infinitescroll('pause');
|
||||
logger.debug("end of jamtracks");
|
||||
|
||||
if(currentPage == 0 && response.jamtracks.length == 0) {
|
||||
$content.append("<div class='no-jamtracks-msg'>There's no jamtracks.</div>") ;
|
||||
}
|
||||
|
||||
if(currentPage > 0) {
|
||||
$noMoreJamtracks.show();
|
||||
// there are bugs with infinitescroll not removing the 'loading'.
|
||||
// it's most noticeable at the end of the list, so whack all such entries
|
||||
$('.infinite-scroll-loader').remove();
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentPage++;
|
||||
buildQuery();
|
||||
registerInfiniteScroll();
|
||||
}
|
||||
}
|
||||
|
||||
function registerInfiniteScroll() {
|
||||
$scroller.infinitescroll({
|
||||
behavior: 'local',
|
||||
navSelector: '#jamtrackScreen .btn-next-pager',
|
||||
nextSelector: '#jamtrackScreen .btn-next-pager',
|
||||
binder: $scroller,
|
||||
dataType: 'json',
|
||||
appendCallback: false,
|
||||
prefill: false,
|
||||
bufferPx: 100,
|
||||
loading: {
|
||||
msg: $('<div class="infinite-scroll-loader">Loading ...</div>'),
|
||||
img: '/assets/shared/spinner.gif'
|
||||
},
|
||||
path: function(page) {
|
||||
return '/api/jamtracks?' + $.param(buildQuery());
|
||||
}
|
||||
},function(json, opts) {
|
||||
handleJamtrackResponse(json);
|
||||
});
|
||||
$scroller.infinitescroll('resume');
|
||||
}
|
||||
|
||||
function playJamtrack(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function addToCartJamtrack(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var params = {id: $(e.target).attr("data-jamtrack-id")};
|
||||
|
||||
rest.addJamtrackToShoppingCart(params)
|
||||
.done(function(response) {
|
||||
context.location = "/client#/shoppingCart";
|
||||
})
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function licenseUSWhy(e) {
|
||||
e.preventDefault();
|
||||
|
||||
app.layout.showDialog('jamtrack-availability-dialog');
|
||||
}
|
||||
|
||||
function registerEvents() {
|
||||
$screen.find('.jamtrack-detail-btn').on("click", showJamtrackDescription);
|
||||
$screen.find('.play-button').on('click', playJamtrack);
|
||||
$screen.find('.jamtrack-add-cart').on('click', addToCartJamtrack);
|
||||
$screen.find('.license-us-why').on('click', licenseUSWhy);
|
||||
}
|
||||
|
||||
function renderJamtracks(data) {
|
||||
$.each(data.jamtracks, function(i, jamtrack) {
|
||||
$.each(jamtrack.tracks, function (index, track) {
|
||||
var inst = '../assets/content/icon_instrument_default24.png';
|
||||
if (track.instrument.id in instrument_logo_map) {
|
||||
inst = instrument_logo_map[track.instrument.id].asset;
|
||||
}
|
||||
track.instrument_url = inst;
|
||||
|
||||
track.instrument_desc = track.instrument.description;
|
||||
if (track.part != "") {
|
||||
track.instrument_desc += " ( " + track.part + " )";
|
||||
}
|
||||
});
|
||||
|
||||
var options = {
|
||||
jamtrack: jamtrack
|
||||
};
|
||||
|
||||
var $jamtrackItem = $(
|
||||
context._.template(
|
||||
$('#template-jamtrack').html(),
|
||||
options,
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
renderJamtrack($jamtrackItem );
|
||||
});
|
||||
|
||||
registerEvents();
|
||||
}
|
||||
|
||||
function showJamtrackDescription(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $description = $(e.target).parent(".detail-arrow").next();
|
||||
if ($description.css("display") == "none") {
|
||||
$description.show();
|
||||
}
|
||||
else {
|
||||
$description.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function renderJamtrack(jamtrack) {
|
||||
$content.append(jamtrack);
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('jamtrack', screenBindings);
|
||||
|
||||
$screen = $("#jamtrack-find-form");
|
||||
$scroller = $screen.find('.content-body-scroller');
|
||||
$content = $screen.find(".jamtrack-content");
|
||||
$genre = $screen.find("#jamtrack_genre");
|
||||
$instrument = $screen.find("#jamtrack_instrument");
|
||||
$availability = $screen.find("#jamtrack_availability");
|
||||
$nextPager = $screen.find("a.btn-next-pager");
|
||||
$noMoreJamtracks = $screen.find("#end-of-jamtrack-list");
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($scroller.length == 0) throw "$scroller must be specified";
|
||||
if($content.length == 0) throw "$content must be specified";
|
||||
if($noMoreJamtracks.length == 0) throw "$noMoreJamtracks must be specified";
|
||||
if($genre.length == 0) throw "$genre must be specified";
|
||||
if($instrument.length == 0) throw "$instrument must be specified";
|
||||
if($availability.length ==0) throw "$availability must be specified";
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})(window,jQuery);
|
||||
|
|
@ -31,5 +31,11 @@ class ModUtils
|
|||
deferred.resolve(shouldShowForName)
|
||||
))
|
||||
return deferred;
|
||||
|
||||
# returns a gear mod by name
|
||||
getGear: (name) =>
|
||||
gear = context.JK.app.currentUser().mods?.gear
|
||||
if gear? then gear[name] else undefined
|
||||
|
||||
# global instance
|
||||
context.JK.ModUtils = new ModUtils()
|
||||
|
|
@ -0,0 +1,511 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.OrderScreen = function(app) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
|
||||
var $screen = null;
|
||||
var $navigation = null;
|
||||
var $billingInfo = null;
|
||||
var $shippingInfo = null;
|
||||
var $paymentMethod = null;
|
||||
var $shippingAddress = null;
|
||||
var $shippingAsBilling = null;
|
||||
var $paymentInfoPanel = null;
|
||||
var $orderPanel = null;
|
||||
var $orderContent = null;
|
||||
var userDetail = null;
|
||||
var step = null;
|
||||
var billing_info = null;
|
||||
var shipping_info = null;
|
||||
var shipping_as_billing = null;
|
||||
|
||||
function beforeShow() {
|
||||
beforeShowPaymentInfo();
|
||||
// moveToOrder();
|
||||
}
|
||||
|
||||
function beforeShowPaymentInfo() {
|
||||
step = 2;
|
||||
renderNavigation();
|
||||
renderAccountInfo();
|
||||
}
|
||||
|
||||
function renderAccountInfo() {
|
||||
rest.getUserDetail()
|
||||
.done(populateAccountInfo)
|
||||
.error(app.ajaxError);
|
||||
}
|
||||
|
||||
function populateAccountInfo(user) {
|
||||
userDetail = user;
|
||||
|
||||
if (userDetail.has_recurly_account) {
|
||||
rest.getBillingInfo()
|
||||
.done(function(response) {
|
||||
$billingInfo.find("#billing-first-name").val(response.first_name);
|
||||
$billingInfo.find("#billing-last-name").val(response.last_name);
|
||||
$billingInfo.find("#billing-address1").val(response.address1);
|
||||
$billingInfo.find("#billing-address2").val(response.address2);
|
||||
$billingInfo.find("#billing-city").val(response.city);
|
||||
$billingInfo.find("#billing-state").val(response.state);
|
||||
$billingInfo.find("#billing-zip").val(response.zip);
|
||||
$billingInfo.find("#billing-country").val(response.country);
|
||||
|
||||
$shippingAddress.find("#shipping-first-name").val(response.first_name);
|
||||
$shippingAddress.find("#shipping-last-name").val(response.last_name);
|
||||
$shippingAddress.find("#shipping-address1").val(response.address1);
|
||||
$shippingAddress.find("#shipping-address2").val(response.address2);
|
||||
$shippingAddress.find("#shipping-city").val(response.city);
|
||||
$shippingAddress.find("#shipping-state").val(response.state);
|
||||
$shippingAddress.find("#shipping-zip").val(response.zip);
|
||||
$shippingAddress.find("#shipping-country").val(response.country);
|
||||
})
|
||||
.error(app.ajaxError);
|
||||
}
|
||||
else {
|
||||
$billingInfo.find("#billing-first-name").val(userDetail.first_name);
|
||||
$billingInfo.find("#billing-last-name").val(userDetail.last_name);
|
||||
$billingInfo.find("#billing-city").val(userDetail.city);
|
||||
$billingInfo.find("#billing-state").val(userDetail.state);
|
||||
$billingInfo.find("#billing-country").val(userDetail.country);
|
||||
|
||||
$shippingAddress.find("#shipping-first-name").val(userDetail.first_name);
|
||||
$shippingAddress.find("#shipping-last-name").val(userDetail.last_name);
|
||||
$shippingAddress.find("#shipping-city").val(userDetail.city);
|
||||
$shippingAddress.find("#shipping-state").val(userDetail.state);
|
||||
$shippingAddress.find("#shipping-country").val(userDetail.country);
|
||||
}
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function next(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// validation
|
||||
var billing_first_name = $billingInfo.find("#billing-first-name").val();
|
||||
var billing_last_name = $billingInfo.find("#billing-last-name").val();
|
||||
var billing_address1 = $billingInfo.find("#billing-address1").val();
|
||||
var billing_address2 = $billingInfo.find("#billing-address2").val();
|
||||
var billing_city = $billingInfo.find("#billing-city").val();
|
||||
var billing_state = $billingInfo.find("#billing-state").val();
|
||||
var billing_zip = $billingInfo.find("#billing-zip").val();
|
||||
var billing_country = $billingInfo.find("#billing-country").val();
|
||||
|
||||
if (!billing_first_name) {
|
||||
$billingInfo.find('#divBillingFirstName .error-text').remove();
|
||||
$billingInfo.find('#divBillingFirstName').addClass("error");
|
||||
$billingInfo.find('#billing-first-name').after("<ul class='error-text'><li>First Name is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingFirstName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_last_name) {
|
||||
$billingInfo.find('#divBillingLastName .error-text').remove();
|
||||
$billingInfo.find('#divBillingLastName').addClass("error");
|
||||
$billingInfo.find('#billing-last-name').after("<ul class='error-text'><li>Last Name is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingLastName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_address1) {
|
||||
$billingInfo.find('#divBillingAddress1 .error-text').remove();
|
||||
$billingInfo.find('#divBillingAddress1').addClass("error");
|
||||
$billingInfo.find('#billing-address1').after("<ul class='error-text'><li>Address is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingAddress1').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_zip) {
|
||||
$billingInfo.find('#divBillingZip .error-text').remove();
|
||||
$billingInfo.find('#divBillingZip').addClass("error");
|
||||
$billingInfo.find('#billing-zip').after("<ul class='error-text'><li>Zip code is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingZip').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_state) {
|
||||
$billingInfo.find('#divBillingState .error-text').remove();
|
||||
$billingInfo.find('#divBillingState').addClass("error");
|
||||
$billingInfo.find('#billing-zip').after("<ul class='error-text'><li>State is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingState').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_city) {
|
||||
$billingInfo.find('#divBillingCity .error-text').remove();
|
||||
$billingInfo.find('#divBillingCity').addClass("error");
|
||||
$billingInfo.find('#billing-city').after("<ul class='error-text'><li>City is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingCity').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_country) {
|
||||
$billingInfo.find('#divBillingCountry .error-text').remove();
|
||||
$billingInfo.find('#divBillingCountry').addClass("error");
|
||||
$billingInfo.find('#billing-country').after("<ul class='error-text'><li>Country is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingCountry').removeClass("error");
|
||||
}
|
||||
|
||||
shipping_as_billing = $shippingAsBilling.is(":checked");
|
||||
var shipping_first_name, shipping_last_name, shipping_address1, shipping_address2;
|
||||
var shipping_city, shipping_state, shipping_zip, shipping_country;
|
||||
|
||||
if (!shipping_as_billing) {
|
||||
shipping_first_name = $shippingAddress.find("#shipping-first-name").val();
|
||||
shipping_last_name = $shippingAddress.find("#shipping-last-name").val();
|
||||
shipping_address1 = $shippingAddress.find("#shipping-address1").val();
|
||||
shipping_address2 = $shippingAddress.find("#shipping-address2").val();
|
||||
shipping_city = $shippingAddress.find("#shipping-city").val();
|
||||
shipping_state = $shippingAddress.find("#shipping-state").val();
|
||||
shipping_zip = $shippingAddress.find("#shipping-zip").val();
|
||||
shipping_country = $shippingAddress.find("#shipping-country").val();
|
||||
|
||||
if (!shipping_first_name) {
|
||||
$shippingAddress.find('#divShippingFirstName .error-text').remove();
|
||||
$shippingAddress.find('#divShippingFirstName').addClass("error");
|
||||
$shippingAddress.find('#shipping-first-name').after("<ul class='error-text'><li>First Name is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingFirstName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_last_name) {
|
||||
$shippingAddress.find('#divShippingLastName .error-text').remove();
|
||||
$shippingAddress.find('#divShippingLastName').addClass("error");
|
||||
$shippingAddress.find('#shipping-last-name').after("<ul class='error-text'><li>Last Name is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingLastName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_address1) {
|
||||
$shippingAddress.find('#divShippingAddress1 .error-text').remove();
|
||||
$shippingAddress.find('#divShippingAddress1').addClass("error");
|
||||
$shippingAddress.find('#shipping-address1').after("<ul class='error-text'><li>Address is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingAddress1').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_zip) {
|
||||
$shippingAddress.find('#divShippingZip .error-text').remove();
|
||||
$shippingAddress.find('#divShippingZip').addClass("error");
|
||||
$shippingAddress.find('#shipping-zip').after("<ul class='error-text'><li>Zip code is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingZip').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_state) {
|
||||
$shippingAddress.find('#divShippingState .error-text').remove();
|
||||
$shippingAddress.find('#divShippingState').addClass("error");
|
||||
$shippingAddress.find('#shipping-zip').after("<ul class='error-text'><li>State is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingState').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_city) {
|
||||
$shippingAddress.find('#divShippingCity .error-text').remove();
|
||||
$shippingAddress.find('#divShippingCity').addClass("error");
|
||||
$shippingAddress.find('#shipping-city').after("<ul class='error-text'><li>City is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingCity').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_country) {
|
||||
$shippingAddress.find('#divShippingCountry .error-text').remove();
|
||||
$shippingAddress.find('#divShippingCountry').addClass("error");
|
||||
$shippingAddress.find('#shipping-country').after("<ul class='error-text'><li>Country is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingAddress.find('#divShippingCountry').removeClass("error");
|
||||
}
|
||||
}
|
||||
|
||||
var card_name = $paymentMethod.find("#card-name").val();
|
||||
var card_number = $paymentMethod.find("#card-number").val();
|
||||
var card_year = $paymentMethod.find("#card_expire-date_3i").val();
|
||||
var card_month = $paymentMethod.find("#card_expire-date_2i").val();
|
||||
var card_verify = $paymentMethod.find("#card-verify").val();
|
||||
|
||||
if (!card_name) {
|
||||
$paymentMethod.find('#divCardName .error-text').remove();
|
||||
$paymentMethod.find('#divCardName').addClass("error");
|
||||
$paymentMethod.find('#card-name').after("<ul class='error-text'><li>Card Name is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$paymentMethod.find('#divCardName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!card_number) {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$paymentMethod.find('#divCardNumber').removeClass("error");
|
||||
}
|
||||
|
||||
if (!card_verify) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card_verify').after("<ul class='error-text'><li>Card Verification Value is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$paymentMethod.find('#divCardVerify').removeClass("error");
|
||||
}
|
||||
|
||||
billing_info = {};
|
||||
shipping_info = {};
|
||||
billing_info.first_name = billing_first_name;
|
||||
billing_info.last_name = billing_last_name;
|
||||
billing_info.address1 = billing_address1;
|
||||
billing_info.address2 = billing_address2;
|
||||
billing_info.city = billing_city;
|
||||
billing_info.state = billing_state;
|
||||
billing_info.country = billing_country;
|
||||
billing_info.zip = billing_zip;
|
||||
billing_info.number = card_number;
|
||||
billing_info.month = card_month;
|
||||
billing_info.year = card_year;
|
||||
billing_info.verification_value = card_verify;
|
||||
|
||||
if (shipping_as_billing) {
|
||||
shipping_info = billing_info;
|
||||
delete shipping_info.number;
|
||||
delete shipping_info.month;
|
||||
delete shipping_info.year;
|
||||
delete shipping_info.verification_value;
|
||||
}
|
||||
else {
|
||||
shipping_info.first_name = shipping_first_name;
|
||||
shipping_info.last_name = shipping_last_name;
|
||||
shipping_info.address1 = shipping_address1;
|
||||
shipping_info.address2 = shipping_address2;
|
||||
shipping_info.city = shipping_city;
|
||||
shipping_info.state = shipping_state;
|
||||
shipping_info.country = shipping_country;
|
||||
shipping_info.zip = shipping_zip;
|
||||
}
|
||||
|
||||
$paymentInfoPanel.find("#payment-info-next").addClass("disabled");
|
||||
$paymentInfoPanel.find("#payment-info-next").off("click");
|
||||
|
||||
if (userDetail.has_recurly_account) {
|
||||
rest.updateBillingInfo(billing_info)
|
||||
.done(function() {
|
||||
})
|
||||
.fail(errorHandling);
|
||||
}
|
||||
else {
|
||||
rest.createRecurlyAccount({billing_info: billing_info})
|
||||
.done(function() {
|
||||
})
|
||||
.fail(errorHandling);
|
||||
}
|
||||
}
|
||||
|
||||
function errorHandling(xhr, ajaxOptions, thrownError) {
|
||||
$.each(xhr.responseJSON.errors, function(key, error) {
|
||||
if (key == 'number') {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if (key == 'verification_value') {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
});
|
||||
|
||||
$paymentInfoPanel.find("#payment-info-next").removeClass("disabled");
|
||||
$paymentInfoPanel.find("#payment-info-next").on("click", next);
|
||||
// moveToOrder();
|
||||
}
|
||||
|
||||
function beforeShowOrder() {
|
||||
step = 3;
|
||||
renderNavigation();
|
||||
populateOrderPage();
|
||||
}
|
||||
|
||||
function clearOrderPage() {
|
||||
$orderContent.empty();
|
||||
}
|
||||
|
||||
function populateOrderPage() {
|
||||
clearOrderPage();
|
||||
|
||||
rest.getShoppingCarts()
|
||||
.done(renderOrderPage)
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function renderOrderPage(carts) {
|
||||
var data = {};
|
||||
|
||||
var sub_total = 0;
|
||||
$.each(carts, function(index, cart) {
|
||||
sub_total += parseFloat(cart.product_info.price) * parseFloat(cart.quantity);
|
||||
});
|
||||
data.sub_total = sub_total.toFixed(2);
|
||||
data.taxes = 12.01;
|
||||
|
||||
data.carts = carts;
|
||||
data.billing_info = billing_info;
|
||||
data.shipping_info = shipping_info;
|
||||
data.shipping_as_billing = shipping_as_billing;
|
||||
var orderContentHtml = $(
|
||||
context._.template(
|
||||
$('#template-order-content').html(),
|
||||
data,
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
|
||||
$orderContent.append(orderContentHtml);
|
||||
|
||||
$orderPanel.find(".change-payment-info").on('click', moveToPaymentInfo);
|
||||
$orderContent.find(".place-order").on('click', placeOrder);
|
||||
}
|
||||
|
||||
function moveToOrder() {
|
||||
$paymentInfoPanel.addClass("hidden");
|
||||
$orderPanel.removeClass("hidden");
|
||||
beforeShowOrder();
|
||||
}
|
||||
|
||||
function moveToPaymentInfo(e) {
|
||||
e.preventDefault();
|
||||
$paymentInfoPanel.removeClass("hidden");
|
||||
$orderPanel.addClass("hidden");
|
||||
beforeShowPaymentInfo();
|
||||
}
|
||||
|
||||
function toggleShippingAsBilling(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var shipping_as_billing = $(e.target).is(':checked');
|
||||
|
||||
if (!shipping_as_billing) {
|
||||
$shippingAddress.removeClass("hidden");
|
||||
}
|
||||
else {
|
||||
$shippingAddress.addClass("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function placeOrder(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function events() {
|
||||
$paymentInfoPanel.find("#payment-info-next").on('click', next);
|
||||
$shippingAsBilling.on('ifChanged', toggleShippingAsBilling);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
}
|
||||
|
||||
function renderNavigation() {
|
||||
$navigation.html("");
|
||||
var navigationHtml = $(
|
||||
context._.template(
|
||||
$('#template-checkout-navigation').html(),
|
||||
{current: step},
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
|
||||
$navigation.append(navigationHtml);
|
||||
}
|
||||
|
||||
function initializeControls() {
|
||||
$("form.payment-info").iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('order', screenBindings);
|
||||
|
||||
$screen = $("#orderScreen");
|
||||
$paymentInfoPanel = $screen.find(".checkout-payment-info");
|
||||
$orderPanel = $screen.find(".order-panel");
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
$billingInfo = $paymentInfoPanel.find(".billing-address");
|
||||
$shippingInfo = $paymentInfoPanel.find(".shipping-address");
|
||||
$paymentMethod = $paymentInfoPanel.find(".payment-method");
|
||||
$shippingAddress = $paymentInfoPanel.find(".shipping-address-detail");
|
||||
$shippingAsBilling = $paymentInfoPanel.find("#shipping-as-billing");
|
||||
$orderContent = $orderPanel.find(".order-content");
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($navigation.length == 0) throw "$navigation must be specified";
|
||||
|
||||
initializeControls();
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})(window,jQuery);
|
||||
|
|
@ -1237,7 +1237,7 @@
|
|||
$languageList = $screen.find('#session-language-list');
|
||||
$sessionPlusMusiciansLabel = $screen.find('label[for="session-plus-musicians"]');
|
||||
$editScheduledSessions = $screen.find('#edit_scheduled_sessions');
|
||||
$btnSelectFiles = $screen.find('.btn-select-files');
|
||||
$btnSelectFiles = $screen.find('#session-notation-file-selection');
|
||||
$selectedFilenames = $screen.find('#selected-filenames');
|
||||
$uploadSpinner = $screen.find('#file-upload-spinner');
|
||||
$policyTypes = $screen.find('input[name="session-policy-type"]');
|
||||
|
|
|
|||
|
|
@ -495,9 +495,6 @@
|
|||
var mixerIds = context.jamClient.SessionGetIDs();
|
||||
var holder = $.extend(true, {}, {mixers: context.jamClient.SessionGetControlState(mixerIds)});
|
||||
mixers = holder.mixers;
|
||||
|
||||
//console.log("mixers", mixers)
|
||||
|
||||
// grab the first mixer, and check the mode
|
||||
|
||||
var newMixerMode;;
|
||||
|
|
@ -884,6 +881,7 @@
|
|||
// particular client, in a particular group, and I'll need to further
|
||||
// identify by track id or something similar.
|
||||
|
||||
|
||||
var mixers = _groupedMixersForClientId(
|
||||
participant.client_id,
|
||||
[
|
||||
|
|
@ -908,6 +906,7 @@
|
|||
oppositeMixer = mixers[ChannelGroupIds.PeerAudioInputMusicGroup][0]
|
||||
}
|
||||
}
|
||||
|
||||
if (mixer) {
|
||||
usedMixers[mixer.id] = true;
|
||||
myTrack = (mixer.group_id === ChannelGroupIds.AudioInputMusicGroup);
|
||||
|
|
@ -982,6 +981,7 @@
|
|||
var keysToDelete = [];
|
||||
for (var key in lookingForMixers) {
|
||||
var clientId = lookingForMixers[key];
|
||||
<<<<<<< HEAD
|
||||
var mixers = _groupedMixersForClientId(
|
||||
clientId,
|
||||
[
|
||||
|
|
@ -1004,6 +1004,27 @@
|
|||
mixer = mixers[ChannelGroupIds.UserMusicInputGroup][0]
|
||||
oppositeMixer = mixers[ChannelGroupIds.PeerAudioInputMusicGroup][0]
|
||||
}
|
||||
=======
|
||||
var mixer = null;
|
||||
if(sessionModel.isMasterMixMode()) {
|
||||
mixer = _mixerForClientId(
|
||||
clientId,
|
||||
[
|
||||
ChannelGroupIds.AudioInputMusicGroup,
|
||||
ChannelGroupIds.PeerAudioInputMusicGroup
|
||||
],
|
||||
usedMixers);
|
||||
}
|
||||
else {
|
||||
// don't pass in used mixers; we need to associate multiple tracks with the same mixer
|
||||
mixer = _mixerForClientId(
|
||||
clientId,
|
||||
[
|
||||
ChannelGroupIds.AudioInputMusicGroup,
|
||||
ChannelGroupIds.UserMusicInputGroup
|
||||
],
|
||||
{});
|
||||
>>>>>>> develop
|
||||
}
|
||||
if (mixer) {
|
||||
var participant = (sessionModel.getParticipant(clientId) || {name:'unknown'}).name;
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@
|
|||
var track = participant.tracks[j];
|
||||
logger.debug("Find:Finding instruments. Participant tracks:", participant.tracks);
|
||||
var inst = context.JK.getInstrumentIcon24(track.instrument_id);
|
||||
instrumentLogoHtml += '<img title="' + track.instrument_id + '" hoveraction="instrument" data-instrument-id="' + track.instrument_id + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentLogoHtml += '<img title="' + context.JK.getInstrumentId(track.instrument_id) + '" hoveraction="instrument" data-instrument-id="' + track.instrument_id + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
}
|
||||
|
||||
var id = participant.user.id;
|
||||
|
|
@ -411,7 +411,7 @@
|
|||
for (j=0; j < user.instrument_list.length; j++) {
|
||||
var instrument = user.instrument_list[j];
|
||||
var inst = context.JK.getInstrumentIcon24(instrument.id);
|
||||
instrumentLogoHtml += '<img title="' + instrument.id + '" hoveraction="instrument" data-instrument-id="' + instrument.id + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentLogoHtml += '<img title="' + context.JK.getInstrumentId(instrument.id) + '" hoveraction="instrument" data-instrument-id="' + instrument.id + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.ShoppingCartScreen = function(app) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
|
||||
var $screen = null;
|
||||
var $content = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
loadShoppingCarts();
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function events() {
|
||||
$screen.find("a.remove-cart").on('click', removeCart);
|
||||
$screen.find("a.proceed-checkout").on('click', proceedCheckout);
|
||||
}
|
||||
|
||||
function proceedCheckout(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!context.JK.currentUserId) {
|
||||
window.location = '/client#/signin';
|
||||
}
|
||||
else {
|
||||
window.location = '/client#/order';
|
||||
}
|
||||
}
|
||||
|
||||
function removeCart(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var options = {};
|
||||
options.id = $(e.target).attr("cart-id");
|
||||
|
||||
rest.removeShoppingCart(options)
|
||||
.done(loadShoppingCarts)
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function clearContent() {
|
||||
$content.empty();
|
||||
}
|
||||
|
||||
function loadShoppingCarts() {
|
||||
clearContent();
|
||||
|
||||
rest.getShoppingCarts()
|
||||
.done(renderShoppingCarts)
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function renderShoppingCarts(carts) {
|
||||
var data = {};
|
||||
var latest_cart = carts[carts.length - 1];
|
||||
|
||||
var $latestCartHtml = "";
|
||||
|
||||
if (latest_cart) {
|
||||
$latestCartHtml = $(
|
||||
context._.template(
|
||||
$('#template-shopping-cart-header').html(),
|
||||
latest_cart,
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
var sub_total = 0;
|
||||
$.each(carts, function(index, cart) {
|
||||
sub_total += parseFloat(cart.product_info.price) * parseFloat(cart.quantity);
|
||||
});
|
||||
data.sub_total = sub_total.toFixed(2);
|
||||
|
||||
data.carts = carts;
|
||||
var $cartsHtml = $(
|
||||
context._.template(
|
||||
$('#template-shopping-cart-body').html(),
|
||||
data,
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
|
||||
$content.append($latestCartHtml).append($cartsHtml);
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('shoppingCart', screenBindings);
|
||||
|
||||
$screen = $("#shoppingCartScreen");
|
||||
$content = $screen.find(".shopping-cart-content");
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($content.length == 0) throw "$content must be specified";
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})(window,jQuery);
|
||||
|
|
@ -88,6 +88,7 @@
|
|||
var instrumentIconMap24 = {};
|
||||
var instrumentIconMap45 = {};
|
||||
var instrumentIconMap256 = {};
|
||||
var notSpecifiedText = "Not specified";
|
||||
|
||||
$.each(icon_map_base, function (instrumentId, icon) {
|
||||
instrumentIconMap24[instrumentId] = {asset: "/assets/content/icon_instrument_" + icon + "24.png", name: instrumentId};
|
||||
|
|
@ -332,24 +333,28 @@
|
|||
|
||||
function showBubble(bubble, $hoverElement) {
|
||||
$hoverElement.attr("bubble-id", bubble.id);
|
||||
bubble.showBubble($hoverElement);
|
||||
bubble.showBubble($hoverElement)
|
||||
.done(function() {
|
||||
|
||||
$(bubble.id()).hover(
|
||||
function () {
|
||||
$(this).data('hovering', true)
|
||||
// do nothing when entering the bubble
|
||||
},
|
||||
function () {
|
||||
$(this).data('hovering', false).fadeOut(100);
|
||||
}
|
||||
);
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
function hideBubble($hoverElement) {
|
||||
|
||||
var bubbleSelector = $hoverElement.attr("bubble-id");
|
||||
|
||||
$(bubbleSelector).hover(
|
||||
function () {
|
||||
// do nothing when entering the bubble
|
||||
},
|
||||
function () {
|
||||
$(this).fadeOut(fadeoutValue);
|
||||
}
|
||||
);
|
||||
|
||||
// first check to see if the user isn't hovering over the hover bubble
|
||||
if (!$(bubbleSelector).is(":hover")) {
|
||||
if (!$(bubbleSelector).data('hovering')) {
|
||||
$(bubbleSelector).fadeOut(fadeoutValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -358,8 +363,10 @@
|
|||
$("[hoveraction='musician']", $parent).hoverIntent({
|
||||
over: function(e) {
|
||||
var bubble = new JK.MusicianHoverBubble($(this).attr('user-id'), e.pageX, e.pageY);
|
||||
|
||||
showBubble(bubble, $(this));
|
||||
|
||||
|
||||
},
|
||||
out: function () { // this registers for leaving the hoverable element
|
||||
hideBubble($(this));
|
||||
|
|
@ -507,6 +514,10 @@
|
|||
return instrumentIconMap256["_default"].asset;
|
||||
};
|
||||
|
||||
context.JK.getInstrumentId = function(instrumentId) {
|
||||
return instrumentId ? instrumentId : notSpecifiedText;
|
||||
}
|
||||
|
||||
// meant to pass in a bunch of images with an instrument-id attribute on them.
|
||||
|
||||
context.JK.setInstrumentAssetPath = function ($elements) {
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@
|
|||
var $bufferIn = null;
|
||||
var $bufferOut = null;
|
||||
var $frameSize = null;
|
||||
var $adjustSettingsLink = null;
|
||||
var $self = $(this);
|
||||
var logger = context.JK.logger;
|
||||
|
||||
var FRAMESIZE_CHANGED = 'frame_buffers.framesize_changed';
|
||||
var BUFFER_IN_CHANGED = 'frame_buffers.buffer_in_changed';
|
||||
var BUFFER_OUT_CHANGED = 'frame_buffers.buffer_out_changed';
|
||||
var ADJUST_GEAR_LINK_CLICKED = 'frame_buffers.adjust_gear_settings_clicked';
|
||||
|
||||
function selectedFramesize() {
|
||||
return parseFloat($frameSize.val());
|
||||
|
|
@ -77,6 +80,12 @@
|
|||
logger.debug("buffer-out changed: " + selectedBufferOut());
|
||||
$self.triggerHandler(BUFFER_OUT_CHANGED, {value: selectedBufferOut()});
|
||||
});
|
||||
|
||||
$adjustSettingsLink.click(function() {
|
||||
logger.debug("adjust-gear-settings clicked");
|
||||
$self.triggerHandler(ADJUST_GEAR_LINK_CLICKED);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function initialize(_$knobs) {
|
||||
|
|
@ -89,6 +98,7 @@
|
|||
$bufferIn = $knobs.find('.select-buffer-in');
|
||||
$bufferOut = $knobs.find('.select-buffer-out');
|
||||
$frameSize = $knobs.find('.select-frame-size');
|
||||
$adjustSettingsLink = $knobs.find('.adjust-gear-settings')
|
||||
|
||||
events();
|
||||
render();
|
||||
|
|
@ -97,6 +107,7 @@
|
|||
this.FRAMESIZE_CHANGED = FRAMESIZE_CHANGED;
|
||||
this.BUFFER_IN_CHANGED = BUFFER_IN_CHANGED;
|
||||
this.BUFFER_OUT_CHANGED = BUFFER_OUT_CHANGED;
|
||||
this.ADJUST_GEAR_LINK_CLICKED = ADJUST_GEAR_LINK_CLICKED;
|
||||
this.initialize = initialize;
|
||||
this.selectedFramesize = selectedFramesize;
|
||||
this.selectedBufferIn = selectedBufferIn;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
var $wizardSteps = null;
|
||||
var $templateSteps = null;
|
||||
var loopbackWizard = null;
|
||||
var adjustGearSettings = null;
|
||||
var inputs = null;
|
||||
|
||||
var self = this;
|
||||
|
|
@ -183,9 +184,10 @@
|
|||
return inputs;
|
||||
}
|
||||
|
||||
function initialize(_loopbackWizard) {
|
||||
function initialize(_loopbackWizard, _adjustGearSettings) {
|
||||
|
||||
loopbackWizard = _loopbackWizard;
|
||||
adjustGearSettings = _adjustGearSettings;
|
||||
|
||||
// on initial page load, we are not in the FTUE. so cancel the FTUE and call FTUESetStatus(true) if needed
|
||||
if(context.jamClient.FTUEGetStatus() == false) {
|
||||
|
|
@ -224,6 +226,7 @@
|
|||
this.createFTUEProfile = createFTUEProfile;
|
||||
this.getWizard = function() {return wizard; }
|
||||
this.getLoopbackWizard = function() { return loopbackWizard; };
|
||||
this.getAdjustGearSettings = function() { return adjustGearSettings; };
|
||||
|
||||
self = this;
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@
|
|||
context.JK = context.JK || {};
|
||||
context.JK.StepDirectMonitoring = function (app) {
|
||||
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
var $step = null;
|
||||
var $directMonitoringBtn = null;
|
||||
var $adjustSettingsDirectMonitor = null;
|
||||
var isPlaying = false;
|
||||
var playCheckInterval = null;
|
||||
var trackDurationMs = null;
|
||||
|
|
@ -83,12 +85,29 @@
|
|||
}
|
||||
}
|
||||
|
||||
function onAdjustGearRequested() {
|
||||
app.layout.showDialog('adjust-gear-speed-dialog').one(EVENTS.DIALOG_CLOSED, function(e, data) {
|
||||
|
||||
var adjustGearTest = data.result;
|
||||
|
||||
if(!data.canceled) {
|
||||
if(adjustGearTest.isGoodFtue()) {
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.debug("adjust-gear-speed was cancelled; ignoring")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function initialize(_$step) {
|
||||
$step = _$step;
|
||||
|
||||
$directMonitoringBtn = $step.find('.test-direct-monitoring');
|
||||
|
||||
$directMonitoringBtn.on('click', togglePlay);
|
||||
$adjustSettingsDirectMonitor = $step.find('.adjust-settings-direct-monitor');
|
||||
$adjustSettingsDirectMonitor.on('click', onAdjustGearRequested)
|
||||
}
|
||||
|
||||
this.handleHelp = handleHelp;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
var VOICE_CHAT = context.JK.VOICE_CHAT;
|
||||
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
|
||||
var gearUtils = context.JK.GearUtils;
|
||||
var modUtils = context.JK.ModUtils;
|
||||
|
||||
var self = null;
|
||||
var $step = null;
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
var frameBuffers = new context.JK.FrameBuffers(app);
|
||||
var gearTest = new context.JK.GearTest(app);
|
||||
var loopbackShowing = false;
|
||||
var adjustGearSettingsShowing = false;
|
||||
var wizard = null;
|
||||
|
||||
// the goal of lastFailureAnalytics and trackedPass are to send only a single AudioTest 'Pass' or 'Failed' event, per FTUE wizard open/close
|
||||
|
|
@ -32,6 +34,8 @@
|
|||
var $inputChannels = null;
|
||||
var $outputChannels = null;
|
||||
var $knobs = null;
|
||||
var $adjustSettingsLink = null;
|
||||
var $adjustGearForIoFail = null;
|
||||
var $scoreReport = null;
|
||||
var $asioInputControlBtn = null;
|
||||
var $asioOutputControlBtn = null;
|
||||
|
|
@ -86,7 +90,7 @@
|
|||
}
|
||||
|
||||
function initializeNextButtonState() {
|
||||
dialog.setNextState(gearTest.isGoodFtue() || dialog.getLoopbackWizard().getGearTest().isGoodFtue());
|
||||
dialog.setNextState(gearTest.isGoodFtue() || dialog.getLoopbackWizard().getGearTest().isGoodFtue() || dialog.getAdjustGearSettings().getGearTest().isGoodFtue());
|
||||
}
|
||||
|
||||
function initializeBackButtonState() {
|
||||
|
|
@ -365,8 +369,9 @@
|
|||
if(dialog.getLoopbackWizard().getGearTest().isGoodFtue()) {
|
||||
gearTest.resetScoreReport();
|
||||
gearTest.showLoopbackDone();
|
||||
context.JK.prodBubble(dialog.getWizard().getNextButton(), 'move-on-loopback-success', {}, {positions:['top']});
|
||||
|
||||
setTimeout(function() {
|
||||
context.JK.prodBubble(dialog.getWizard().getNextButton(), 'can-move-on', {}, {positions:['top'], offsetParent: dialog.getWizard().getDialog()});
|
||||
}, 300);
|
||||
}
|
||||
|
||||
initializeNextButtonState();
|
||||
|
|
@ -379,6 +384,42 @@
|
|||
})
|
||||
}
|
||||
|
||||
function onAdjustGearRequested()
|
||||
{
|
||||
if(gearTest.isScoring()) {logger.debug("ignoring adjust-gear request while scoring"); return false;}
|
||||
|
||||
app.layout.showDialog('adjust-gear-speed-dialog').one(EVENTS.DIALOG_CLOSED, function(e, data) {
|
||||
adjustGearSettingsShowing = false;
|
||||
|
||||
var adjustGearTest = data.result;
|
||||
|
||||
if(!data.canceled) {
|
||||
if(adjustGearTest.isGoodFtue()) {
|
||||
// update our own frame buffers to reflect any changes made by the adjust dialog
|
||||
frameBuffers.setFramesize(context.jamClient.FTUEGetFrameSize())
|
||||
frameBuffers.setBufferIn(context.jamClient.FTUEGetInputLatency())
|
||||
frameBuffers.setBufferOut(context.jamClient.FTUEGetOutputLatency())
|
||||
|
||||
gearTest.resetScoreReport();
|
||||
gearTest.showGearAdjustmentDone();
|
||||
|
||||
setTimeout(function() {
|
||||
context.JK.prodBubble(dialog.getWizard().getNextButton(), 'can-move-on', {}, {positions:['top'], offsetParent: dialog.getWizard().getDialog()});
|
||||
}, 300);
|
||||
}
|
||||
|
||||
initializeNextButtonState();
|
||||
initializeBackButtonState();
|
||||
}
|
||||
else {
|
||||
logger.debug("adjust-gear-speed was cancelled; ignoring")
|
||||
}
|
||||
})
|
||||
|
||||
adjustGearSettingsShowing = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function initializeFormElements() {
|
||||
if (!deviceInformation) throw "devices are not initialized";
|
||||
|
||||
|
|
@ -486,6 +527,7 @@
|
|||
function invalidateScore() {
|
||||
gearTest.invalidateScore();
|
||||
dialog.getLoopbackWizard().getGearTest().invalidateScore();
|
||||
dialog.getAdjustGearSettings().getGearTest().invalidateScore();
|
||||
initializeNextButtonState();
|
||||
}
|
||||
|
||||
|
|
@ -755,6 +797,7 @@
|
|||
validDevice = autoSelectMinimumValidChannels();
|
||||
|
||||
if (!validDevice) {
|
||||
$adjustSettingsLink.hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -774,6 +817,11 @@
|
|||
shownOutputProdOnce = true;
|
||||
}
|
||||
|
||||
// further, check if we have both inputs and outputs defined; if so, show ? to allow launch of adjust gear settings dialog
|
||||
if(modUtils.getGear('show_frame_options')) {
|
||||
$adjustSettingsLink.show();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -821,11 +869,12 @@
|
|||
}
|
||||
|
||||
// handle framesize/buffers
|
||||
if (inputBehavior && (inputBehavior.showKnobs || outputBehavior.showKnobs)) {
|
||||
if (inputBehavior && (inputBehavior.showKnobs || outputBehavior.showKnobs || modUtils.getGear('show_frame_options'))) {
|
||||
$knobs.show();
|
||||
}
|
||||
else {
|
||||
$knobs.hide();
|
||||
$adjustSettingsLink.hide();
|
||||
}
|
||||
|
||||
// handle ASIO visibility
|
||||
|
|
@ -865,36 +914,9 @@
|
|||
jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
|
||||
}
|
||||
|
||||
|
||||
function updateDefaultBuffers() {
|
||||
|
||||
// handle specific framesize settings
|
||||
if(selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm')) {
|
||||
var framesize = frameBuffers.selectedFramesize();
|
||||
|
||||
if(framesize == 2.5) {
|
||||
logger.debug("setting default buffers to 1/1");
|
||||
frameBuffers.setBufferIn('1');
|
||||
frameBuffers.setBufferOut('1');
|
||||
}
|
||||
else if(framesize == 5) {
|
||||
logger.debug("setting default buffers to 3/2");
|
||||
frameBuffers.setBufferIn('3');
|
||||
frameBuffers.setBufferOut('2');
|
||||
}
|
||||
else {
|
||||
logger.debug("setting default buffers to 6/5");
|
||||
frameBuffers.setBufferIn('6');
|
||||
frameBuffers.setBufferOut('5');
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.debug("setting default buffers to 0/0");
|
||||
frameBuffers.setBufferIn(0);
|
||||
frameBuffers.setBufferOut(0);
|
||||
}
|
||||
|
||||
jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
|
||||
jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
|
||||
gearUtils.updateDefaultBuffers(selectedDeviceInfo, frameBuffers)
|
||||
}
|
||||
|
||||
// refocused affects how IO testing occurs.
|
||||
|
|
@ -940,11 +962,26 @@
|
|||
}
|
||||
}
|
||||
|
||||
function prodUserToTweakASIOSettings($btn) {
|
||||
setTimeout(function() {
|
||||
context.JK.prodBubble($btn, 'tweak-asio-settings', {}, {positions:['top']});
|
||||
}, 300)
|
||||
}
|
||||
|
||||
function onGearTestFail(e, data) {
|
||||
renderScoringStopped();
|
||||
gearUtils.postDiagnostic(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, true);
|
||||
|
||||
if(data.reason == "latency") {
|
||||
|
||||
console.log("selectedDeviceInfo", selectedDeviceInfo)
|
||||
if(selectedDeviceInfo.input.info.type.indexOf('Win32_asio') > -1) {
|
||||
prodUserToTweakASIOSettings($asioInputControlBtn)
|
||||
}
|
||||
else if(selectedDeviceInfo.output.info.type.indexOf('Win32_asio') > -1) {
|
||||
prodUserToTweakASIOSettings($asioOutputControlBtn)
|
||||
}
|
||||
|
||||
storeLastFailureForAnalytics(context.JK.detectOS(), context.JK.GA.AudioTestFailReasons.latency, data.latencyScore);
|
||||
}
|
||||
else if(data.reason = "io") {
|
||||
|
|
@ -973,11 +1010,13 @@
|
|||
|
||||
var specificResolutions = [];
|
||||
|
||||
if(selectedDeviceInfo.input.behavior.type.indexOf('Win32_asio') > -1 || selectedDeviceInfo.output.behavior.type.indexOf('Win32_asio') > -1) {
|
||||
if(selectedDeviceInfo.input.info.type.indexOf('Win32_asio') > -1 || selectedDeviceInfo.output.info.type.indexOf('Win32_asio') > -1) {
|
||||
// specificResolutions.push("Read over this <a rel='external' href='https://jamkazam.desk.com/customer/portal/articles/1723489-jamkazam-thinks-your-gear-is-disconnected---windows-only'>article</a>")
|
||||
specificResolutions.push("Select the ASIO SETTINGS... button and try different settings.");
|
||||
}
|
||||
|
||||
if(selectedDeviceInfo.input.behavior.type == 'Win32_wdm' || selectedDeviceInfo.output.behavior.type == 'Win32_wdm') {
|
||||
if(selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm') {
|
||||
// specificResolutions.push("Read over this <a rel='external' href='https://jamkazam.desk.com/customer/portal/articles/1723489-jamkazam-thinks-your-gear-is-disconnected---windows-only'>article</a>")
|
||||
specificResolutions.push("Change the Frame, Buffer In, or Buffer Out settings.");
|
||||
}
|
||||
|
||||
|
|
@ -1063,7 +1102,7 @@
|
|||
}
|
||||
|
||||
function onFocus() {
|
||||
if(validDevice && !loopbackShowing && !gearTest.isScoring() && getSelectedInputs().length > 0 && getSelectedOutputs().length == 2 ) {
|
||||
if(validDevice && !loopbackShowing && !adjustGearSettingsShowing && !gearTest.isScoring() && getSelectedInputs().length > 0 && getSelectedOutputs().length == 2 ) {
|
||||
scheduleRescanSystem(function() { attemptScore(true); }, 3000, false)
|
||||
}
|
||||
}
|
||||
|
|
@ -1160,6 +1199,8 @@
|
|||
$inputChannels = $step.find('.input-ports');
|
||||
$outputChannels = $step.find('.output-ports');
|
||||
$knobs = $step.find('.frame-and-buffers');
|
||||
$adjustSettingsLink = $knobs.find('.adjust-gear-settings')
|
||||
$adjustGearForIoFail = $step.find(".adjust-gear-for-io-fail")
|
||||
$scoreReport = $step.find('.results');
|
||||
$asioInputControlBtn = $step.find('.asio-settings-input-btn');
|
||||
$asioOutputControlBtn = $step.find('.asio-settings-output-btn');
|
||||
|
|
@ -1175,6 +1216,7 @@
|
|||
.on(frameBuffers.FRAMESIZE_CHANGED, onFramesizeChanged)
|
||||
.on(frameBuffers.BUFFER_IN_CHANGED, onBufferInChanged)
|
||||
.on(frameBuffers.BUFFER_OUT_CHANGED, onBufferOutChanged)
|
||||
.on(frameBuffers.ADJUST_GEAR_LINK_CLICKED, onAdjustGearRequested)
|
||||
|
||||
gearTest.initialize($scoreReport, true)
|
||||
$(gearTest)
|
||||
|
|
@ -1182,6 +1224,7 @@
|
|||
.on(gearTest.GEAR_TEST_DONE, onGearTestDone)
|
||||
.on(gearTest.GEAR_TEST_FAIL, onGearTestFail)
|
||||
.on(gearTest.GEAR_TEST_INVALIDATED_ASYNC, onGearTestInvalidated)
|
||||
$adjustGearForIoFail.click(onAdjustGearRequested);
|
||||
}
|
||||
|
||||
this.getLastAudioTestFailAnalytics = getLastAudioTestFailAnalytics;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
var $resultsText = null;
|
||||
var $unknownText = null;
|
||||
var $loopbackCompleted = null;
|
||||
var $adjustGearSpeedCompleted = null;
|
||||
var $adjustGearForIoFail = null;
|
||||
var $ioScoreSection = null;
|
||||
var $latencyScoreSection = null;
|
||||
|
||||
|
|
@ -78,6 +80,10 @@
|
|||
medianIOClass = 'acceptable';
|
||||
}
|
||||
|
||||
// uncomment one to force a particular type of I/O failure
|
||||
// medianIOClass = "bad";
|
||||
// stdIOClass = "bad"
|
||||
|
||||
// take worst between median or std
|
||||
var ioClassToNumber = {bad: 2, acceptable: 1, good: 0}
|
||||
var aggregrateIOClass = ioClassToNumber[stdIOClass] > ioClassToNumber[medianIOClass] ? stdIOClass : medianIOClass;
|
||||
|
|
@ -240,6 +246,10 @@
|
|||
latencyClass = 'unknown';
|
||||
}
|
||||
|
||||
// uncomment these two lines to fail test due to latency
|
||||
// latencyClass = "bad";
|
||||
// validLatency = false;
|
||||
|
||||
validLatencyScore = validLatency;
|
||||
|
||||
if(refocused) {
|
||||
|
|
@ -300,7 +310,7 @@
|
|||
logger.debug("gear_test: onInvalidAudioDevice")
|
||||
asynchronousInvalidDevice = true;
|
||||
$self.triggerHandler(GEAR_TEST_INVALIDATED_ASYNC);
|
||||
context.JK.Banner.showAlert('Invalid Audio Device', 'It appears this audio device is not currently connected. Attach the device to your computer and restart the application, or select a different device.')
|
||||
context.JK.Banner.showAlert('Invalid Audio Device', 'It appears this audio device is not currently connected. Attach the device to your computer and restart the application, or select a different device.<br/><br/>If you think your gear is connected and working, this <a rel="external" href="https://jamkazam.desk.com/customer/portal/articles/1723489-jamkazam-thinks-your-gear-is-disconnected---windows-only">support article</a> can help.')
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -308,6 +318,10 @@
|
|||
$loopbackCompleted.show();
|
||||
}
|
||||
|
||||
function showGearAdjustmentDone() {
|
||||
$adjustGearSpeedCompleted.show();
|
||||
}
|
||||
|
||||
function resetScoreReport() {
|
||||
$ioHeader.hide();
|
||||
$latencyHeader.hide();
|
||||
|
|
@ -322,6 +336,7 @@
|
|||
$resultsText.removeAttr('scored');
|
||||
$unknownText.hide();
|
||||
$loopbackCompleted.hide();
|
||||
$adjustGearSpeedCompleted.hide();
|
||||
$ioScoreSection.removeClass('good acceptable bad unknown starting skip');
|
||||
$latencyScoreSection.removeClass('good acceptable bad unknown starting')
|
||||
}
|
||||
|
|
@ -398,6 +413,8 @@
|
|||
$resultsText = $scoreReport.find('.results-text');
|
||||
$unknownText = $scoreReport.find('.unknown-text');
|
||||
$loopbackCompleted = $scoreReport.find('.loopback-completed')
|
||||
$adjustGearSpeedCompleted = $scoreReport.find('.adjust-gear-speed-completed');
|
||||
$adjustGearForIoFail = $scoreReport.find(".adjust-gear-for-io-fail")
|
||||
$latencyScoreSection = $scoreReport.find('.latency-score-section');
|
||||
|
||||
function onGearTestStart(e, data) {
|
||||
|
|
@ -514,6 +531,7 @@
|
|||
this.attemptScore = attemptScore;
|
||||
this.resetScoreReport = resetScoreReport;
|
||||
this.showLoopbackDone = showLoopbackDone;
|
||||
this.showGearAdjustmentDone = showGearAdjustmentDone;
|
||||
this.invalidateScore = invalidateScore;
|
||||
this.isValidLatencyScore = isValidLatencyScore;
|
||||
this.isValidIOScore = isValidIOScore;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,54 @@
|
|||
return loadedDevices;
|
||||
}
|
||||
|
||||
gearUtils.updateDefaultBuffers = function(selectedDeviceInfo, frameBuffers) {
|
||||
function hasWDMAssociated() {
|
||||
return selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm')
|
||||
}
|
||||
|
||||
function hasASIOAssociated() {
|
||||
return selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_asio' || selectedDeviceInfo.output.info.type == 'Win32_asio')
|
||||
}
|
||||
|
||||
// handle specific framesize settings
|
||||
if(hasWDMAssociated() || hasASIOAssociated()) {
|
||||
var framesize = frameBuffers.selectedFramesize();
|
||||
|
||||
if(framesize == 2.5) {
|
||||
// if there is a WDM device, start off at 1/1 due to empirically observed issues with 0/0
|
||||
if(hasWDMAssociated()) {
|
||||
logger.debug("setting default buffers to 1/1");
|
||||
frameBuffers.setBufferIn('1');
|
||||
frameBuffers.setBufferOut('1');
|
||||
}
|
||||
else {
|
||||
// otherwise, it's ASIO, so go with 0/0
|
||||
logger.debug("setting default buffers to 0/0");
|
||||
frameBuffers.setBufferIn('0');
|
||||
frameBuffers.setBufferOut('0');
|
||||
}
|
||||
}
|
||||
else if(framesize == 5) {
|
||||
logger.debug("setting default buffers to 3/2");
|
||||
frameBuffers.setBufferIn('3');
|
||||
frameBuffers.setBufferOut('2');
|
||||
}
|
||||
else {
|
||||
logger.debug("setting default buffers to 6/5");
|
||||
frameBuffers.setBufferIn('6');
|
||||
frameBuffers.setBufferOut('5');
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.debug("setting default buffers to 0/0");
|
||||
frameBuffers.setBufferIn(0);
|
||||
frameBuffers.setBufferOut(0);
|
||||
}
|
||||
|
||||
context.jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
|
||||
context.jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
|
||||
}
|
||||
|
||||
gearUtils.ftueSummary = function(operatingSystem, deviceInformation, selectedDeviceInfo, gearTest, frameBuffers, isAutomated) {
|
||||
return {
|
||||
os: operatingSystem,
|
||||
|
|
|
|||
|
|
@ -58,35 +58,7 @@
|
|||
}
|
||||
|
||||
function updateDefaultBuffers() {
|
||||
|
||||
// handle specific framesize settings
|
||||
if(selectedDeviceInfo && (selectedDeviceInfo.input.info.type == 'Win32_wdm' || selectedDeviceInfo.output.info.type == 'Win32_wdm')) {
|
||||
var framesize = frameBuffers.selectedFramesize();
|
||||
|
||||
if(framesize == 2.5) {
|
||||
logger.debug("setting default buffers to 1/1");
|
||||
frameBuffers.setBufferIn('1');
|
||||
frameBuffers.setBufferOut('1');
|
||||
}
|
||||
else if(framesize == 5) {
|
||||
logger.debug("setting default buffers to 3/2");
|
||||
frameBuffers.setBufferIn('3');
|
||||
frameBuffers.setBufferOut('2');
|
||||
}
|
||||
else {
|
||||
logger.debug("setting default buffers to 6/5");
|
||||
frameBuffers.setBufferIn('6');
|
||||
frameBuffers.setBufferOut('5');
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.debug("setting default buffers to 0/0");
|
||||
frameBuffers.setBufferIn(0);
|
||||
frameBuffers.setBufferOut(0);
|
||||
}
|
||||
|
||||
jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
|
||||
jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
|
||||
gearUtils.updateDefaultBuffers(selectedDeviceInfo, frameBuffers)
|
||||
}
|
||||
|
||||
function onFramesizeChanged() {
|
||||
|
|
|
|||
|
|
@ -217,6 +217,10 @@
|
|||
return $currentWizardStep;
|
||||
}
|
||||
|
||||
function getDialog() {
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
function initialize(_$dialog, _$wizardSteps, _STEPS, _options) {
|
||||
$dialog = _$dialog;
|
||||
dialogName = $dialog.attr('layout-id');
|
||||
|
|
@ -239,6 +243,7 @@
|
|||
this.onCloseDialog = onCloseDialog;
|
||||
this.onBeforeShow = onBeforeShow;
|
||||
this.onAfterHide = onAfterHide;
|
||||
this.getDialog = getDialog;
|
||||
this.initialize = initialize;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,252 @@
|
|||
.checkout-navigation {
|
||||
padding: 20px 0px;
|
||||
.nav-signin, .nav-payment-info, .nav-place-order {
|
||||
width: 30%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.nav-signin {
|
||||
margin-left: 5%;
|
||||
}
|
||||
|
||||
.nav-place-order {
|
||||
margin-right: 5%;
|
||||
}
|
||||
|
||||
.nav-text {
|
||||
font-size: 17px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.nav-text.selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-arrow {
|
||||
float: left;
|
||||
margin-left: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.checkout-signin, .checkout-payment-info, .checkout-place-order {
|
||||
padding: 30px;
|
||||
|
||||
.signin-form {
|
||||
padding: 10px;
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.signin-password {
|
||||
margin-left: 33px;
|
||||
}
|
||||
|
||||
.login-error {
|
||||
background-color: #330000;
|
||||
border: 1px solid #990000;
|
||||
padding:4px;
|
||||
|
||||
div.actions {
|
||||
margin-top:10px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-error-msg {
|
||||
display:none;
|
||||
margin-top:10px;
|
||||
text-align:center;
|
||||
color:#F00;
|
||||
font-size:11px;
|
||||
}
|
||||
|
||||
.login-error .login-error-msg {
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
|
||||
form.payment-info {
|
||||
width: 100%;
|
||||
|
||||
input[type="text"] {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.billing-address {
|
||||
float: left;
|
||||
width: 50%;
|
||||
|
||||
h2.billing-caption {
|
||||
margin: 20px 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.billing-label {
|
||||
padding-top: 8px;
|
||||
width: 30%;
|
||||
float: left;
|
||||
text-align: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.billing-value {
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-method {
|
||||
float: left;
|
||||
width: 50%;
|
||||
|
||||
h2.payment-method-caption {
|
||||
margin: 20px 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
padding-top: 8px;
|
||||
width: 35%;
|
||||
float: left;
|
||||
text-align: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.save-card-checkbox {
|
||||
float:left;
|
||||
display:block;
|
||||
margin-right:5px;
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-address {
|
||||
float: left;
|
||||
width: 50%;
|
||||
|
||||
h2.shipping-address-label {
|
||||
margin: 20px 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.shipping-as-billing {
|
||||
float:left;
|
||||
display:block;
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
.divBillingHelper {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.shipping-label {
|
||||
padding-top: 8px;
|
||||
width: 30%;
|
||||
float: left;
|
||||
text-align: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.shipping-value {
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.order-panel {
|
||||
padding: 30px;
|
||||
|
||||
.order-header {
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.order-content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.order-left-page {
|
||||
float: left;
|
||||
width: 60%;
|
||||
|
||||
.payment-info-page {
|
||||
padding: 5px;
|
||||
|
||||
.info-caption-link {
|
||||
.caption-text {
|
||||
float: left;
|
||||
}
|
||||
.caption-link {
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.address-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.payment-method-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
.order-items-page {
|
||||
padding: 5px;
|
||||
|
||||
.cart-item-caption {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-caption#header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cart-item-price {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-quantity {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.order-right-page {
|
||||
float: right;
|
||||
width: 35%;
|
||||
text-align: center;
|
||||
|
||||
.order-total {
|
||||
color: #ed3618;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,6 +49,9 @@
|
|||
*= require ./terms
|
||||
*= require ./createSession
|
||||
*= require ./feed
|
||||
*= require ./jamtrack
|
||||
*= require ./shoppingCart
|
||||
*= require ./checkout
|
||||
*= require ./genreSelector
|
||||
*= require ./sessionList
|
||||
*= require ./searchResults
|
||||
|
|
|
|||
|
|
@ -7,6 +7,15 @@
|
|||
z-index:5;
|
||||
}
|
||||
|
||||
.header-shopping-cart {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
|
||||
img {
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
div[layout="header"] h1 {
|
||||
cursor:pointer;
|
||||
width: 247px;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@
|
|||
.homecard.musicians {
|
||||
background-image: url(/assets/content/bkg_home_musicians.jpg);
|
||||
}
|
||||
.homecard.jamtrack {
|
||||
background-image: url(/assets/content/bkg_home_jamtracks.jpg);
|
||||
}
|
||||
|
||||
.homebox-info {
|
||||
position: absolute;
|
||||
|
|
@ -93,6 +96,9 @@
|
|||
.homecard.musicians.hover {
|
||||
background-image: url(/assets/content/bkg_home_musicians_x.jpg);
|
||||
}
|
||||
.homecard.jamtrack.hover {
|
||||
background-image: url(/assets/content/bkg_home_jamtracks_x.jpg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
|
||||
&.musician-bubble {
|
||||
width:425px;
|
||||
width:438px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
#jamtrackScreen {
|
||||
a.jamtrack_help {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
margin: 4px 0px 0px 60px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.no-jamtracks-msg {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.jamtrack-record {
|
||||
border-bottom: 1px solid black;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.jamtrack-detail {
|
||||
float: left;
|
||||
width: 50%;
|
||||
padding: 10px 0px;
|
||||
|
||||
.detail-label {
|
||||
width: 40%;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
width: 50%;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.copyright-value {
|
||||
width: 40%;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.detail-arrow {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.jamtrack-description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.jamtrack-detail-btn {
|
||||
cursor: pointer;
|
||||
margin-top: 5px;
|
||||
margin-right: 5px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack-tracks {
|
||||
float: left;
|
||||
width: 25%;
|
||||
padding: 10px 0px;
|
||||
|
||||
.tracks-caption {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.track-instrument {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.instrument-image {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.instrument-desc {
|
||||
margin-top: 6px;
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack-action {
|
||||
float: left;
|
||||
width: 25%;
|
||||
padding: 10px 0px;
|
||||
text-align: center;
|
||||
|
||||
.play-button {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.jamtrack-price {
|
||||
margin-top: 5px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.jamtrack-add-cart, .jamtrack-add-cart-disabled {
|
||||
margin: 8px 0px;
|
||||
}
|
||||
|
||||
.jamtrack-license {
|
||||
margin-left: 20%;
|
||||
margin-right: 20%;
|
||||
font-size: 13px;
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#shoppingCartScreen {
|
||||
|
||||
.content-body {
|
||||
padding: 50px 20px 20px 20px;
|
||||
|
||||
.checkout-image {
|
||||
width: 10%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.checkout-desc {
|
||||
width: 90%;
|
||||
float: left;
|
||||
|
||||
div {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
div#note {
|
||||
font-style: italic;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-item-caption {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-caption#header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cart-item-price {
|
||||
width: 15%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-quantity {
|
||||
width: 15%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-actions {
|
||||
width: 20%;
|
||||
text-align: center;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
overflow: auto;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.shopping-sub-total {
|
||||
width: 65%;
|
||||
float: left;
|
||||
text-align: right;
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.no-cart-items {
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,10 @@
|
|||
width:45%;
|
||||
}
|
||||
|
||||
.adjust-gear-settings {
|
||||
display:none;
|
||||
margin-left:4px;
|
||||
}
|
||||
|
||||
.buffers {
|
||||
float:left;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,11 @@
|
|||
display:inline;
|
||||
}
|
||||
}
|
||||
&[data-type=adjust-gear-speed] {
|
||||
span.conditional[data-type=adjust-gear-speed] {
|
||||
display:inline;
|
||||
}
|
||||
}
|
||||
.io, .latency {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -47,7 +52,7 @@
|
|||
padding: 8px;
|
||||
}
|
||||
|
||||
.loopback-completed {
|
||||
.loopback-completed, .adjust-gear-speed-completed {
|
||||
display:none;
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +120,14 @@
|
|||
display: none
|
||||
}
|
||||
|
||||
span.io-failure {
|
||||
display:none;
|
||||
}
|
||||
|
||||
%span.no-io-failure {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
&[latency-score="unknown"] {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -159,6 +172,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
&[io-rate-score="bad"], &[io-var-score="bad"] {
|
||||
span.io-failure {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
span.no-io-failure {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
|
||||
&[latency-score="unknown"] {
|
||||
li.success {
|
||||
display: none;
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@
|
|||
}
|
||||
|
||||
.watch-video {
|
||||
margin-top: 26px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.help-content {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,160 @@
|
|||
@import "client/common.css.scss";
|
||||
@charset "UTF-8";
|
||||
#adjust-gear-speed-dialog {
|
||||
min-height: 420px;
|
||||
max-height: 420px;
|
||||
width:800px;
|
||||
|
||||
h2 {
|
||||
color: #FFFFFF;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
margin-bottom: 6px;
|
||||
white-space:nowrap;
|
||||
|
||||
}
|
||||
|
||||
h2.settings {
|
||||
display:inline;
|
||||
position:absolute;
|
||||
left:0;
|
||||
margin-left:0; // override global .settings from sessions.css
|
||||
}
|
||||
|
||||
.ftue-box {
|
||||
background-color: #222222;
|
||||
font-size: 13px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.dialog-inner {
|
||||
line-height: 1.3em;
|
||||
width:800px;
|
||||
padding:25px;
|
||||
font-size:15px;
|
||||
color:#aaa;
|
||||
@include border_box_sizing;
|
||||
|
||||
}
|
||||
|
||||
.dialog-column {
|
||||
|
||||
@include border_box_sizing;
|
||||
|
||||
&:nth-of-type(1) {
|
||||
width:75%;
|
||||
margin-top:38px;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
width:25%;
|
||||
float:right;
|
||||
}
|
||||
}
|
||||
|
||||
.speed-options {
|
||||
display:inline-block;
|
||||
width:60%;
|
||||
margin:auto;
|
||||
margin-left:25%;
|
||||
}
|
||||
|
||||
.speed-option {
|
||||
@include border_box_sizing;
|
||||
float:left;
|
||||
width:33%;
|
||||
text-align:center;
|
||||
|
||||
.iradio_minimal {
|
||||
margin:auto;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
label {
|
||||
display:inline-block;
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.speed-text {
|
||||
margin:10px 0;
|
||||
}
|
||||
|
||||
.run-test-btn {
|
||||
margin-top:5px;
|
||||
margin-left:25px;
|
||||
left:40%;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.frame-and-buffers {
|
||||
display:inline-block;
|
||||
margin-left:30%;
|
||||
|
||||
.framesize {
|
||||
width:auto;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.buffers {
|
||||
width:auto;
|
||||
display:inline-block;
|
||||
margin-left:20px;
|
||||
}
|
||||
h2 {
|
||||
display:inline-block;
|
||||
line-height:18px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.easydropdown-wrapper {
|
||||
display:inline-block;
|
||||
top:-3px;
|
||||
margin-left:8px;
|
||||
}
|
||||
|
||||
|
||||
.select-frame-size {
|
||||
margin-left:-2px;
|
||||
}
|
||||
}
|
||||
|
||||
.help-text {
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
.basic {
|
||||
margin:0 5px 20px 0;
|
||||
}
|
||||
.advanced {
|
||||
display:none;
|
||||
border-width:1px 0 0 0;
|
||||
border-style:solid;
|
||||
border-color:white;
|
||||
padding-top:20px;
|
||||
margin:0 5px 0 0;
|
||||
.help-text {
|
||||
text-align:left;
|
||||
}
|
||||
}
|
||||
|
||||
.test-results-header {
|
||||
position:static;
|
||||
}
|
||||
|
||||
|
||||
.ftue-box.results {
|
||||
margin-top:20px;
|
||||
height: 268px !important;
|
||||
padding:0;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
h2.results-text-header {
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
class ApiJamtracksController < ApiController
|
||||
|
||||
# have to be signed in currently to see this screen
|
||||
before_filter :api_signed_in_user
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
data = JamTrack.index current_user, params
|
||||
|
||||
@jamtracks = data[0]
|
||||
@next = data[1]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
class ApiRecurlyController < ApiController
|
||||
|
||||
before_filter :api_signed_in_user
|
||||
respond_to :json
|
||||
|
||||
# create Recurly account
|
||||
def create_account
|
||||
logger.debug(params[:billing_info])
|
||||
if current_user.recurly_code.nil?
|
||||
@account = Recurly::Account.create(
|
||||
account_code: current_user.id,
|
||||
email: current_user.email,
|
||||
first_name: current_user.first_name,
|
||||
last_name: current_user.last_name,
|
||||
address: {
|
||||
city: current_user.city,
|
||||
state: current_user.state,
|
||||
country: current_user.country
|
||||
}
|
||||
)
|
||||
else
|
||||
@account = Recurly::Account.find(current_user.recurly_code)
|
||||
end
|
||||
|
||||
if @account.errors.any?
|
||||
response.status = 404
|
||||
else
|
||||
current_user.recurly_code = @account.account_code
|
||||
current_user.save
|
||||
|
||||
@account.billing_info = params[:billing_info]
|
||||
@account.billing_info.save
|
||||
|
||||
logger.debug @account
|
||||
end
|
||||
respond_with @account
|
||||
|
||||
rescue Recurly::Error, NoMethodError => e
|
||||
render :json => { :message => e.inspect }, :status => 404
|
||||
end
|
||||
|
||||
# get Recurly account
|
||||
def get_account
|
||||
@account = Recurly::Account.find(current_user.reculry_code)
|
||||
respond_with @account
|
||||
rescue Recurly::Error, NoMethodError => e
|
||||
render :json => { message: ValidationMessages::RECURLY_ERROR}, :status => 404
|
||||
end
|
||||
|
||||
# update Recurly account
|
||||
def update_account
|
||||
if current_user.recurly_code.nil?
|
||||
@account = Recurly::Account.create(
|
||||
account_code: current_user.id,
|
||||
email: current_user.email,
|
||||
first_name: current_user.first_name,
|
||||
last_name: current_user.last_name,
|
||||
address: {
|
||||
city: current_user.city,
|
||||
state: current_user.state,
|
||||
country: current_user.country
|
||||
}
|
||||
)
|
||||
else
|
||||
@account = Recurly::Account.get(current_user.recurly_code)
|
||||
end
|
||||
|
||||
@account.first_name = current_user.first_name
|
||||
@account.last_name = current_user.last_name
|
||||
@account.email = current_user.email
|
||||
@account.update
|
||||
|
||||
if @account.errors.any?
|
||||
response.status = 404
|
||||
else
|
||||
current_user.recurly_code = @account.account_code
|
||||
current_user.save
|
||||
end
|
||||
respond_with @account
|
||||
|
||||
rescue Recurly::Error, NoMethodError => e
|
||||
render :json => { message: ValidationMessages::RECURLY_ERROR}, :status => 404
|
||||
end
|
||||
|
||||
# get subscription
|
||||
def get_subscription
|
||||
@account = Recurly::Acount.find(current_user.reculry_code)
|
||||
respond_with @account.subscriptions.last
|
||||
rescue Recurly::Error, NoMethodError => e
|
||||
render :json => { message: ValidationMessages::RECURLY_GET_ACCOUNT_ERROR}, :status => 404
|
||||
end
|
||||
|
||||
# create subscription
|
||||
def create_subscription
|
||||
end
|
||||
|
||||
# get Billing Information
|
||||
def billing_info
|
||||
if current_user.recurly_code.nil?
|
||||
render :json => { message: ValidationMessages::RECURLY_ACCOUNT_ERROR }, :status => 404 and return
|
||||
else
|
||||
@account = Recurly::Account.find(current_user.recurly_code)
|
||||
logger.debug @account
|
||||
respond_with @account.billing_info
|
||||
end
|
||||
rescue Recurly::Error, NoMethodError => e
|
||||
render :json => { message: ValidationMessages::RECURLY_ERROR}, :status => 404
|
||||
end
|
||||
|
||||
# update Billing Information
|
||||
def update_billing_info
|
||||
if current_user.recurly_code.nil?
|
||||
render :json => { message: ValidationMessages::RECURLY_ACCOUNT_ERROR }, :status => 404 and return
|
||||
else
|
||||
if params[:first_name].blank? or params[:last_name].blank? or params[:number].blank? or params[:year].blank? or params[:month].blank? or params[:verification_value].blank?
|
||||
render :json => { message: ValidationMessages::RECURLY_PARAMETER_ERROR }, :status => 404 and return
|
||||
end
|
||||
@account = Recurly::Acount.find(current_user.reculry_code)
|
||||
@account.billing_info = params
|
||||
@account.billing_info.save
|
||||
|
||||
if @account.erros.any?
|
||||
response.status = :unprocessable_entity
|
||||
end
|
||||
|
||||
respond_with @account
|
||||
end
|
||||
rescue Recurly::Error, NoMethodError => e
|
||||
render :json => { message: ValidationMessages::RECURLY_ERROR}, :status => 404
|
||||
end
|
||||
|
||||
def place_order
|
||||
if current_user.recurly_code.nil?
|
||||
render :json => { message: ValidationMessages::RECURLY_ACCOUNT_ERROR }, :status => 404 and return
|
||||
else
|
||||
if params[:first_name].blank? or params[:last_name].blank? or params[:number].blank? or params[:year].blank? or params[:month].blank? or params[:verification_value].blank?
|
||||
render :json => { message: ValidationMessages::RECURLY_PARAMETER_ERROR }, :status => 404 and return
|
||||
end
|
||||
@account = Recurly::Account.find(current_user.recurly_code)
|
||||
@account.billing_info = params
|
||||
@account.billing_info.save
|
||||
|
||||
# create subscription.
|
||||
|
||||
if @account.erros.any?
|
||||
response.status = :unprocessable_entity
|
||||
end
|
||||
|
||||
respond_with @account
|
||||
end
|
||||
rescue Recurly::Error, NoMethodError => e
|
||||
render :json => { message: ValidationMessages::RECURLY_ERROR}, :status => 404
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
class ApiShoppingCartsController < ApiController
|
||||
|
||||
before_filter :api_signed_in_user
|
||||
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
@carts = current_user.shopping_carts
|
||||
end
|
||||
|
||||
def add_jamtrack
|
||||
jam_track = JamTrack.find_by_id(params[:id])
|
||||
|
||||
# verify JamTrack exists
|
||||
if jam_track.nil?
|
||||
raise StateError, "Invalid JamTrack."
|
||||
end
|
||||
|
||||
@cart = ShoppingCart.create current_user, jam_track
|
||||
|
||||
if @cart.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
respond_with @cart
|
||||
else
|
||||
respond_with @cart, responder: ApiResponder, :statue => 201
|
||||
end
|
||||
end
|
||||
|
||||
def update_cart
|
||||
@cart = ShoppingCart.find_by_id params[:id]
|
||||
|
||||
#verify Cart exists
|
||||
raise StateError, "Invalid Cart." if @cart.nil?
|
||||
|
||||
@cart.quantity = params[:quantity]
|
||||
|
||||
if @cart.errors.any?
|
||||
response.statue = :unprocessable_entity
|
||||
respond_with @cart
|
||||
else
|
||||
respond_with @cart, responder: ApiResponder, :status => 200
|
||||
end
|
||||
end
|
||||
|
||||
def remove_cart
|
||||
@cart = current_user.shopping_carts.find_by_id(params[:id])
|
||||
raise StateError, "Invalid Cart." if @cart.nil?
|
||||
|
||||
@cart.destroy
|
||||
respond_with responder: ApiResponder, :status => 204
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
require 'sanitize'
|
||||
class ApiUsersController < ApiController
|
||||
|
||||
before_filter :api_signed_in_user, :except => [:create, :show, :signup_confirm, :auth_session_create, :complete, :finalize_update_email, :isp_scoring, :add_play]
|
||||
before_filter :api_signed_in_user, :except => [:create, :show, :signup_confirm, :auth_session_create, :complete, :finalize_update_email, :isp_scoring, :add_play, :crash_dump]
|
||||
before_filter :auth_user, :only => [:session_settings_show, :session_history_index, :session_user_history_index, :update, :delete,
|
||||
:liking_create, :liking_destroy, # likes
|
||||
:following_create, :following_show, :following_destroy, # followings
|
||||
|
|
|
|||
|
|
@ -25,20 +25,27 @@ module MusicSessionHelper
|
|||
else
|
||||
unique_users = music_session.unique_users
|
||||
if sharer && unique_users.exists?(sharer)
|
||||
"LIVE SESSION: #{sharer.name}#{additional_member_count(unique_users)}"
|
||||
"LIVE SESSION: #{sharer.name}#{additional_member_count(unique_users, sharer)}"
|
||||
else
|
||||
"LIVE SESSION: #{music_session.creator.name}#{additional_member_count(unique_users)}"
|
||||
"LIVE SESSION: #{music_session.creator.name}#{additional_member_count(unique_users, music_session.creator)}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def additional_member_count(unique_users)
|
||||
def additional_member_count(unique_users, target_user)
|
||||
length = unique_users.length
|
||||
if length < 2
|
||||
""
|
||||
else
|
||||
" & #{length} OTHERS"
|
||||
other_length = length - 1
|
||||
if other_length == 1
|
||||
other_user_in_array = unique_users - [target_user]
|
||||
other_user = other_user_in_array[0]
|
||||
" & #{other_user.name}"
|
||||
else
|
||||
" & #{length - 1} OTHERS"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -23,22 +23,29 @@ module RecordingHelper
|
|||
if claimed_recording.recording.band
|
||||
"RECORDING: #{claimed_recording.recording.band.name}"
|
||||
else
|
||||
unique_users = claimed_recording.recording.users
|
||||
if sharer && unique_users.exists?(sharer)
|
||||
"RECORDING: #{sharer.name}#{additional_member_count(unique_users)}"
|
||||
unique_users = claimed_recording.recording.users.uniq
|
||||
if sharer && unique_users.include?(sharer)
|
||||
"RECORDING: #{sharer.name}#{additional_member_count(unique_users, sharer)}"
|
||||
else
|
||||
"RECORDING: #{claimed_recording.user.name}#{additional_member_count(unique_users)}"
|
||||
"RECORDING: #{claimed_recording.user.name}#{additional_member_count(unique_users, claimed_recording.user)}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def additional_member_count(unique_users)
|
||||
def additional_member_count(unique_users, target_user)
|
||||
length = unique_users.length
|
||||
if length < 2
|
||||
""
|
||||
else
|
||||
" & #{length} OTHERS"
|
||||
other_length = length - 1
|
||||
if other_length == 1
|
||||
other_user_in_array = unique_users - [target_user]
|
||||
other_user = other_user_in_array[0]
|
||||
" & #{other_user.name}"
|
||||
else
|
||||
" & #{length - 1} OTHERS"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
node :next do |page|
|
||||
@next
|
||||
end
|
||||
|
||||
node :jamtracks do |page|
|
||||
partial "api_jamtracks/show", object: @jamtracks
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
object @jamtrack
|
||||
|
||||
attributes :id, :name, :description, :recording_type, :original_artist, :songwriter, :publisher, :sales_region, :price
|
||||
|
||||
node :genres do |item|
|
||||
[item.genre.description] # XXX: need to return single genre; not array
|
||||
end
|
||||
|
||||
node :added_cart do |item|
|
||||
current_user.shopping_carts.map(&:cart_id).include? item.id
|
||||
end
|
||||
|
||||
child(:jam_track_tracks => :tracks) {
|
||||
attributes :id, :part, :instrument
|
||||
}
|
||||
|
||||
child(:licensor => :licensor) {
|
||||
attributes :id, :name
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue