From 0907c1acd1554d919891b5b79cc3ee9b5e09181d Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Thu, 19 Feb 2015 01:06:50 -0600 Subject: [PATCH 01/22] VRFS-2785 : Factory recurly client into ruby project. Fix references and specs as appropriate. --- ruby/Gemfile | 1 + ruby/lib/jam_ruby.rb | 1 + ruby/lib/jam_ruby/init.rb | 17 ++++++++++++++++- .../lib => ruby/lib/jam_ruby}/recurly_client.rb | 2 ++ ruby/spec/factories.rb | 1 + .../spec/jam_ruby}/recurly_client_spec.rb | 2 +- web/app/controllers/api_recurly_controller.rb | 2 +- web/spec/controllers/api_recurly_spec.rb | 6 +----- 8 files changed, 24 insertions(+), 8 deletions(-) rename {web/lib => ruby/lib/jam_ruby}/recurly_client.rb (97%) rename {web/spec/managers => ruby/spec/jam_ruby}/recurly_client_spec.rb (99%) diff --git a/ruby/Gemfile b/ruby/Gemfile index 7a31165d1..8ef539d9a 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -49,6 +49,7 @@ gem 'iso-639' gem 'rubyzip' gem 'sanitize' gem 'influxdb', '0.1.8' +gem 'recurly' group :test do gem 'simplecov', '~> 0.7.1' diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index b94d7d9a2..e147eadc6 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -62,6 +62,7 @@ require "jam_ruby/resque/scheduled/stats_maker" require "jam_ruby/resque/google_analytics_event" require "jam_ruby/resque/batch_email_job" require "jam_ruby/mq_router" +require "jam_ruby/recurly_client" require "jam_ruby/base_manager" require "jam_ruby/connection_manager" require "jam_ruby/version" diff --git a/ruby/lib/jam_ruby/init.rb b/ruby/lib/jam_ruby/init.rb index adf32cf04..d74b80b5e 100644 --- a/ruby/lib/jam_ruby/init.rb +++ b/ruby/lib/jam_ruby/init.rb @@ -1,3 +1,18 @@ # initialize actionmailer ActionMailer::Base.raise_delivery_errors = true -ActionMailer::Base.view_paths = File.expand_path('../../jam_ruby/app/views/', __FILE__) \ No newline at end of file +ActionMailer::Base.view_paths = File.expand_path('../../jam_ruby/app/views/', __FILE__) + +# Use Private API Keys to communicate with Recurly's API v2. See https://docs.recurly.com/api/basics/authentication to learn more. +case JamRuby::Environment + when 'production' + Recurly.api_key = "7d623daabfc2434fa2a893bb008eb3e6" + Recurly.subdomain = 'jamkazam' + when 'development' + Recurly.api_key = "7d623daabfc2434fa2a893bb008eb3e6" + Recurly.subdomain = 'jamkazam-development' + else + Recurly.api_key = "4631527f203b41848523125b3ae51341" + Recurly.subdomain = 'jamkazam-test' +end + +Recurly.default_currency = 'USD' diff --git a/web/lib/recurly_client.rb b/ruby/lib/jam_ruby/recurly_client.rb similarity index 97% rename from web/lib/recurly_client.rb rename to ruby/lib/jam_ruby/recurly_client.rb index 4992814cb..419e3a377 100644 --- a/web/lib/recurly_client.rb +++ b/ruby/lib/jam_ruby/recurly_client.rb @@ -8,9 +8,11 @@ module JamRuby options = account_hash(current_user, billing_info) account = nil begin + #puts "Recurly.api_key: #{Recurly.api_key}" account = Recurly::Account.create(options) raise RecurlyClientError.new(account.errors) if account.errors.any? rescue Recurly::Error, NoMethodError => x + puts "Error: #{x} : #{Kernel.caller}" raise RecurlyClientError, x.to_s else if account diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index 42418a699..8c940bd0b 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -734,6 +734,7 @@ FactoryGirl.define do licensor_royalty_amount 0.999 pro_royalty_amount 0.999 available true + plan_code 'jamtrack-acdc-backinblack' genre JamRuby::Genre.first association :licensor, factory: :jam_track_licensor diff --git a/web/spec/managers/recurly_client_spec.rb b/ruby/spec/jam_ruby/recurly_client_spec.rb similarity index 99% rename from web/spec/managers/recurly_client_spec.rb rename to ruby/spec/jam_ruby/recurly_client_spec.rb index 8b1825cba..1cf58722f 100644 --- a/web/spec/managers/recurly_client_spec.rb +++ b/ruby/spec/jam_ruby/recurly_client_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' -require "recurly_client" +require "jam_ruby/recurly_client" describe RecurlyClient do let(:jamtrack) { FactoryGirl.create(:jam_track) } #let(:client) { RecurlyClient.new } diff --git a/web/app/controllers/api_recurly_controller.rb b/web/app/controllers/api_recurly_controller.rb index 575366d55..cd0aa4b55 100644 --- a/web/app/controllers/api_recurly_controller.rb +++ b/web/app/controllers/api_recurly_controller.rb @@ -1,4 +1,4 @@ -require 'recurly_client' +require 'jam_ruby/recurly_client' class ApiRecurlyController < ApiController before_filter :api_signed_in_user before_filter :create_client diff --git a/web/spec/controllers/api_recurly_spec.rb b/web/spec/controllers/api_recurly_spec.rb index f2a79d552..fb0eeabfd 100644 --- a/web/spec/controllers/api_recurly_spec.rb +++ b/web/spec/controllers/api_recurly_spec.rb @@ -1,13 +1,9 @@ require 'spec_helper' -require 'recurly_client' -#require 'recurly/account' +require 'jam_ruby/recurly_client' describe ApiRecurlyController, :type=>:controller do render_views - # let(:user) { FactoryGirl.create(:user) } - # let(:jamtrack) { FactoryGirl.create(:jam_track) } - before(:each) do @user = FactoryGirl.create(:user) #@jamtrack = FactoryGirl.create(:jam_track) From bcd3785b4506b06e373a686542b31c45566ff4d9 Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Thu, 19 Feb 2015 16:40:19 -0600 Subject: [PATCH 02/22] VRFS-2785 : Update recurly client with refund functionality. Unit test to verify. --- ruby/lib/jam_ruby/recurly_client.rb | 40 +++++++++++++++++++++++ ruby/spec/jam_ruby/recurly_client_spec.rb | 18 ++++++++++ 2 files changed, 58 insertions(+) diff --git a/ruby/lib/jam_ruby/recurly_client.rb b/ruby/lib/jam_ruby/recurly_client.rb index 419e3a377..eb70824c9 100644 --- a/ruby/lib/jam_ruby/recurly_client.rb +++ b/ruby/lib/jam_ruby/recurly_client.rb @@ -70,6 +70,46 @@ module JamRuby account end + def refund_user_subscription(current_user, jam_track) + jam_track_right=JamRuby::JamTrackRight.where("user_id=? AND jam_track_id=?", current_user.id, jam_track.id).first + if jam_track_right + refund_subscription(jam_track_right) + else + raise RecurlyClientError, "The user #{current_user} does not have a subscription to #{jam_track}" + end + end + + def refund_subscription(jam_track_right) + account = get_account(jam_track_right.user) + if (account.present?) + terminated = false + begin + jam_track = jam_track_right.jam_track + account.subscriptions.find_each do |subscription| + puts "subscription.plan.plan_code: #{subscription.plan.plan_code} / #{jam_track.plan_code} / #{subscription.plan.plan_code == jam_track.plan_code}" + if(subscription.plan.plan_code == jam_track.plan_code) + subscription.terminate(:full) + raise RecurlyClientError.new(subscription.errors) if subscription.errors.any? + terminated = true + end + end + + if terminated + jam_track_right.destroy() + else + raise RecurlyClientError, "Subscription '#{jam_track.plan_code}' not found for this user; could not issue refund." + end + + rescue Recurly::Error, NoMethodError => x + raise RecurlyClientError, x.to_s + end + + else + raise RecurlyClientError, "Could not find account to refund order." + end + account + end + def place_order(current_user, jam_track) account = get_account(current_user) if (account.present?) diff --git a/ruby/spec/jam_ruby/recurly_client_spec.rb b/ruby/spec/jam_ruby/recurly_client_spec.rb index 1cf58722f..82217851d 100644 --- a/ruby/spec/jam_ruby/recurly_client_spec.rb +++ b/ruby/spec/jam_ruby/recurly_client_spec.rb @@ -98,6 +98,24 @@ describe RecurlyClient do @user.jam_track_rights.last.jam_track.id.should eq(@jamtrack.id) end + it "can refund subscription" do + @client.find_or_create_account(@user, @billing_info) + + # Place order: + expect{@client.place_order(@user, @jamtrack)}.not_to raise_error() + active_subs=@client.get_account(@user).subscriptions.find_all{|t|t.state=='active'} + @jamtrack.reload + @jamtrack.jam_track_rights.should have(1).items + + # Refund: + expect{@client.refund_user_subscription(@user, @jamtrack)}.not_to raise_error() + active_subs=@client.get_account(@user).subscriptions.find_all{|t|t.state=='active'} + active_subs.should have(0).items + + @jamtrack.reload + @jamtrack.jam_track_rights.should have(0).items + end + it "detects error on double order" do @client.find_or_create_account(@user, @billing_info) expect{@client.place_order(@user, @jamtrack)}.not_to raise_error() From e662c95fba9c33f2c3bb764054f3b312e27d7de1 Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Thu, 19 Feb 2015 16:41:09 -0600 Subject: [PATCH 03/22] VRFS-2785 : Add Jam Track Right (purchased jam track) to admin ui. Hook up a refund action. --- admin/Gemfile | 1 + admin/app/admin/jam_track_right.rb | 87 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 admin/app/admin/jam_track_right.rb diff --git a/admin/Gemfile b/admin/Gemfile index 7502a288e..6f5c0b21e 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -74,6 +74,7 @@ gem 'sanitize' gem 'slim' gem 'influxdb', '0.1.8' gem 'influxdb-rails', '0.1.10' +gem 'recurly' group :libv8 do gem 'libv8', "~> 3.11.8" diff --git a/admin/app/admin/jam_track_right.rb b/admin/app/admin/jam_track_right.rb new file mode 100644 index 000000000..5e7c3687b --- /dev/null +++ b/admin/app/admin/jam_track_right.rb @@ -0,0 +1,87 @@ +require 'jam_ruby/recurly_client' +ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do + + menu :label => 'Purchased JamTracks', :parent => 'JamTracks' + + config.sort_order = 'updated_at DESC' + config.batch_actions = false + + #form :partial => 'form' + + index do + default_actions + + column "Order" do |right| + link_to("Place", order_admin_jam_track_right_path(right)) + " | " + + link_to("Refund", refund_admin_jam_track_right_path(right)) + end + + column "Last Name" do |right| + right.user.last_name + end + column "First Name" do |right| + right.user.first_name + end + column "Jam Track" do |right| + link_to(right.jam_track.name, admin_jam_track_right_path(right.jam_track)) + # right.jam_track + end + column "Plan Code" do |right| + + right.jam_track.plan_code + end + + + end + + form do |f| + f.inputs 'New Jam Track Right' do + f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false + f.input :user, :required=>true, collection: User.all, include_blank: false + end + f.actions + end + + member_action :order, :method => :get do + right = JamTrackRight.where("id=?",params[:id]).first + user = right.user + jam_track = right.jam_track + client = RecurlyClient.new + billing_info = { + first_name: user.first_name, + last_name: user.last_name, + address1: 'Test Address 1', + address2: 'Test Address 2', + city: user.city, + state: user.state, + country: user.country, + zip: '12345', + number: '4111-1111-1111-1111', + month: '08', + year: '2017', + verification_value: '111' + } + + begin + client.find_or_create_account(user, billing_info) + client.place_order(user, jam_track) + rescue RecurlyClientError=>x + redirect_to admin_jam_track_rights_path, notice: "Could not order #{jam_track} for #{user.to_s}: #{x.errors.inspect}" + else + redirect_to admin_jam_track_rights_path, notice: "Placed order of #{jam_track} for #{user.to_s}." + end + end + + member_action :refund, :method => :get do + right = JamTrackRight.where("id=?",params[:id]).first + client = RecurlyClient.new + + begin + client.refund_user_subscription(right.user, right.jam_track) + rescue RecurlyClientError=>x + redirect_to admin_jam_track_rights_path, notice: "Could not issue refund on #{right.jam_track} for #{right.user.to_s}: #{x.errors.inspect}" + else + redirect_to admin_jam_track_rights_path, notice: "Issued full refund on #{right.jam_track} for #{right.user.to_s}" + end + end +end \ No newline at end of file From 9d70400e91f350ff2d3892352cba196cdbd7fd4c Mon Sep 17 00:00:00 2001 From: Seth Call Date: Fri, 20 Feb 2015 09:50:03 -0600 Subject: [PATCH 04/22] * VRFS-2806 - disallow concurrent open of dialog --- web/app/assets/javascripts/session.js | 29 ++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 655fac730..91e5565d6 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -94,6 +94,7 @@ var $mixModeDropdown = null; var $templateMixerModeChange = null; var $closePlaybackRecording = null; + var $openBackingTrack = null; var mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup]; var rest = context.JK.Rest(); @@ -139,6 +140,8 @@ function afterShow(data) { + $openBackingTrack.removeClass('disabled'); + if(!context.JK.JamServer.connected) { promptLeave = false; app.notifyAlert("Not Connected", 'To create or join a session, you must be connected to the server.'); @@ -1925,6 +1928,13 @@ } function handleBackingTrackSelectedCallback(result) { + + $openBackingTrack.removeClass('disabled'); + + if(!sessionModel.inSession()) { + return; + } + if(result.success) { logger.debug("backing track selected: " + result.file); @@ -1937,8 +1947,6 @@ .fail(function(jqXHR) { app.notifyServerError(jqXHR, "Unable to Open BackingTrack For Playback"); }) - - } else { logger.debug("no backing track selected") @@ -2286,6 +2294,12 @@ } function openBackingTrack(e) { + + if($openBackingTrack.is('.disabled')) { + logger.debug("backing track dialog already open") + return false; + } + // just ignore the click if they are currently recording for now if(sessionModel.recordingModel.isRecording()) { app.notify({ @@ -2296,13 +2310,8 @@ return false; } + $openBackingTrack.addClass('disabled'); context.jamClient.ShowSelectBackingTrackDialog("window.JK.HandleBackingTrackSelectedCallback"); - - //app.layout.showDialog('open-backing-track-dialog').one(EVENTS.DIALOG_CLOSED, function(e, data) { - // if(!data.cancel && data.result){ - // sessionModel.setBackingTrack(data.result); - // } - //}) return false; } @@ -2323,6 +2332,7 @@ } function openBackingTrackFile(e) { + // just ignore the click if they are currently recording for now if(sessionModel.recordingModel.isRecording()) { app.notify({ @@ -2611,7 +2621,7 @@ $('#recording-start-stop').on('click', startStopRecording); $('#open-a-recording').on('click', openRecording); $('#open-a-jamtrack').on('click', openJamTrack); - $('#open-a-backingtrack').on('click', openBackingTrack); + $openBackingTrack.on('click', openBackingTrack); $('#open-a-metronome').on('click', openMetronome); $('#session-invite-musicians').on('click', inviteMusicians); $('#session-invite-musicians2').on('click', inviteMusicians); @@ -2656,6 +2666,7 @@ $mixModeDropdown = $screen.find('select.monitor-mode') $templateMixerModeChange = $('#template-mixer-mode-change'); $closePlaybackRecording = $('#close-playback-recording') + $openBackingTrack = $('#open-a-backingtrack'); events(); From ea482da0dc1ddf4cc35a8816d3fb091f89fc8c88 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Fri, 20 Feb 2015 10:01:11 -0600 Subject: [PATCH 05/22] * VRFS-2808 - prevent duplicate attempt to open recording --- .../javascripts/dialog/localRecordingsDialog.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/web/app/assets/javascripts/dialog/localRecordingsDialog.js b/web/app/assets/javascripts/dialog/localRecordingsDialog.js index d08911d7c..10fdae9a1 100644 --- a/web/app/assets/javascripts/dialog/localRecordingsDialog.js +++ b/web/app/assets/javascripts/dialog/localRecordingsDialog.js @@ -7,6 +7,7 @@ var rest = context.JK.Rest(); var showing = false; var perPage = 10; + var openingRecording = false; function tbody() { return $('#local-recordings-dialog table.local-recordings tbody'); @@ -22,6 +23,7 @@ function beforeShow() { + openingRecording = false; emptyList(); resetPagination(); showing = true; @@ -89,6 +91,12 @@ function registerStaticEvents() { $('#local-recordings-dialog table.local-recordings tbody').on('click', 'tr', function(e) { + if(openingRecording) { + // prevent double-click spam + logger.debug("localRecordingDialog: ignoring duplicate open attempt") + return false; + } + var localState = $(this).attr('data-local-state'); if(localState == 'MISSING') { @@ -109,6 +117,8 @@ { var claimedRecording = $(this).data('server-model'); + openingRecording = true; + // tell the server we are about to start a recording rest.startPlayClaimedRecording({id: context.JK.CurrentSessionModel.id(), claimed_recording_id: claimedRecording.id}) .done(function(response) { @@ -146,6 +156,9 @@ app.notifyServerError(jqXHR, "Unable to Open Recording For Playback"); }) + .always(function() { + openingRecording = false; + }) } From 40eea6319e1650c2d336040ed1f7605ad909d98b Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Fri, 20 Feb 2015 10:40:23 -0600 Subject: [PATCH 06/22] Add recurly dependency. --- websocket-gateway/Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/websocket-gateway/Gemfile b/websocket-gateway/Gemfile index 3e32bbc4c..77ce57cc3 100644 --- a/websocket-gateway/Gemfile +++ b/websocket-gateway/Gemfile @@ -54,6 +54,7 @@ gem 'language_list' gem 'rubyzip' gem 'sanitize' gem 'influxdb', '0.1.8' +gem 'recurly' group :development do gem 'pry' From 00d8244c6a72632d7faf1a28eaf71a32571bca38 Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Fri, 20 Feb 2015 16:40:23 -0600 Subject: [PATCH 07/22] VRFS-2786 : Change disabled text for jam track to say "Purchased". Update unit test as well. --- web/app/views/clients/_jamtrack.html.haml | 2 +- web/spec/features/jamtrack_shopping_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/app/views/clients/_jamtrack.html.haml b/web/app/views/clients/_jamtrack.html.haml index a45e932fe..2573197b3 100644 --- a/web/app/views/clients/_jamtrack.html.haml +++ b/web/app/views/clients/_jamtrack.html.haml @@ -69,7 +69,7 @@ .jamtrack-price {{"$ " + data.jamtrack.price}} = "{% if (data.jamtrack.added_cart) { %}" - %a.jamtrack-add-cart-disabled.button-grey.button-disabled{href: "javascript:void(0)"} Added to Cart + %a.jamtrack-add-cart-disabled.button-grey.button-disabled{href: "javascript:void(0)"} Purchased = "{% } else { %}" %a.jamtrack-add-cart.button-orange{href: "#", "data-jamtrack-id" => "{{data.jamtrack.id}}"} Add to Cart = "{% }; %}" diff --git a/web/spec/features/jamtrack_shopping_spec.rb b/web/spec/features/jamtrack_shopping_spec.rb index 85684725d..049f0101a 100644 --- a/web/spec/features/jamtrack_shopping_spec.rb +++ b/web/spec/features/jamtrack_shopping_spec.rb @@ -53,7 +53,7 @@ describe "JamTrack Shopping", :js => true, :type => :feature, :capybara_feature end if options[:added_cart] - jamtrack_record.find('a.jamtrack-add-cart-disabled', text: 'Added to Cart') + jamtrack_record.find('a.jamtrack-add-cart-disabled', text: 'Purchased') else jamtrack_record.find('a.jamtrack-add-cart.button-orange', text: 'Add to Cart') end From dcf3706099eb3346ba5b62ae31bd37c27b438a8a Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Fri, 20 Feb 2015 17:53:18 -0600 Subject: [PATCH 08/22] VRFS-2798 : Hide/show shopping cart icon depending on contents. --- web/app/assets/javascripts/layout.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/web/app/assets/javascripts/layout.js b/web/app/assets/javascripts/layout.js index 6c40f596d..ab1c98813 100644 --- a/web/app/assets/javascripts/layout.js +++ b/web/app/assets/javascripts/layout.js @@ -275,6 +275,15 @@ $expandedPanelContents.animate({"height": expandedPanelHeight + "px"}, opts.animationDuration); } + function displayCartIcon(carts) { + var cartLink = $("a[href='" + "/client#/shoppingCart" + "']") + if (carts.length > 0) { + cartLink.removeClass("hidden") + } else { + cartLink.addClass("hidden") + } + } + function layoutHeader(screenWidth, screenHeight) { var width = screenWidth - 2 * opts.gutter; var height = opts.headerHeight - opts.gutter; @@ -287,6 +296,8 @@ left: left + "px" }; $('[layout="header"]').css(css); + + rest.getShoppingCarts().done(displayCartIcon) } function layoutNotify(screenWidth, screenHeight) { From 1dbfdf0546b65eb5941bd21413ead6956468f4ee Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 23 Feb 2015 10:45:10 -0600 Subject: [PATCH 09/22] * VRFS-2811 - read loop state when drawing track --- web/app/assets/javascripts/session.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 91e5565d6..018b8e72a 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -1045,6 +1045,7 @@ gainPercent: 0, muteClass: 'muted', showLoop: isOpener && !sessionModel.isPlayingRecording(), + loopState: mixer.loop, mixerId: "", avatarClass: 'avatar-recording', preMasteredClass: "" @@ -1795,7 +1796,8 @@ if(trackData.showLoop) { var $trackIconLoop = $track.find('.track-icon-loop') - var $trackIconLoopCheckbox = $trackIconLoop.find('input') + var $trackIconLoopCheckbox = $trackIconLoop.find('input'); + $trackIconLoopCheckbox.prop('checked', trackData.loopState); context.JK.checkbox($trackIconLoopCheckbox) $trackIconLoopCheckbox.on('ifChanged', function() { From ae920c5a1a82953a22697b0da2580af0d6dc61ac Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 23 Feb 2015 10:56:22 -0600 Subject: [PATCH 10/22] * stop play issued before close of backing track --- web/app/assets/javascripts/session.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 018b8e72a..19078c5f3 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -2474,6 +2474,7 @@ }); // '' closes all open backing tracks + context.jamClient.SessionStopPlay(); context.jamClient.SessionCloseBackingTrackFile(''); return false; From d89e2f8e569d70e94d45308316ad4d94a19a60f6 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 23 Feb 2015 15:00:57 -0600 Subject: [PATCH 11/22] * VRFS-2818 - mute and volume faders control both mixer/personal simultaneously. more work required for moving of input tracks affecting backing tracks personal mix --- web/app/assets/javascripts/session.js | 56 +++++++++++++++++-------- web/app/views/clients/_help.html.slim | 2 +- web/app/views/dialogs/_banner.html.slim | 2 +- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 19078c5f3..d91ebf0d5 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -578,7 +578,6 @@ function _updateMixers() { masterMixers = context.jamClient.SessionGetAllControlState(true); personalMixers = context.jamClient.SessionGetAllControlState(false); - context.jamClient //logger.debug("masterMixers", masterMixers) //logger.debug("personalMixers", personalMixers) @@ -602,10 +601,15 @@ var personalMixer = personalMixers[i]; if(personalMixer.group_id == ChannelGroupIds.MediaTrackGroup) { - continue; + // the reason we do this is because some media tracks have same ID in both master and personal moe + personalMixer.uniqueId = 'P--' + personalMixer.id + allMixers[personalMixer.uniqueId] = personalMixer + } + else { + allMixers[personalMixer.id] = personalMixer + } - allMixers[personalMixer.id] = personalMixer // populate other side of mixer pair @@ -1021,6 +1025,9 @@ // if it's a locally opened track (MediaTrackGroup), then we can say this person is the opener var isOpener = mixer.group_id == ChannelGroupIds.MediaTrackGroup; + if(isOpener) { + var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL); + } var shortFilename = context.JK.getNameOfFile(backingTrack.filename); if(!sessionModel.isPlayingRecording()) { @@ -1060,14 +1067,14 @@ trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; - trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) trackData.mediaTrackOpener = isOpener; trackData.mediaControlsDisabled = !isOpener; trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener; - _addRecordingTrack(trackData, mixer); + _addRecordingTrack(trackData, mixer, oppositeMixer); }); } @@ -1123,6 +1130,9 @@ name = oneOfTheTracks.instrument; } + if(isOpener) { + var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL); + } // Default trackData to participant + no Mixer state. var trackData = { trackId: oneOfTheTracks.id, @@ -1146,14 +1156,14 @@ } trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; - trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) trackData.mediaTrackOpener = isOpener; trackData.mediaControlsDisabled = !isOpener; trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener; - _addRecordingTrack(trackData); + _addRecordingTrack(trackData, mixer, oppositeMixer); }); if(!noCorrespondingTracks && jamTracks.length > 0) { @@ -1223,6 +1233,9 @@ // _addRecordingTrack(trackData); + if(isOpener) { + var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL); + } // Default trackData to participant + no Mixer state. var trackData = { @@ -1248,7 +1261,7 @@ } trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; - trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) trackData.mediaTrackOpener = isOpener; @@ -1256,7 +1269,7 @@ trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener; - _addRecordingTrack(trackData, mixer); + _addRecordingTrack(trackData, mixer, oppositeMixer); }// if setFormFromMetronome() } @@ -1323,6 +1336,10 @@ name = oneOfTheTracks.user.first_name + ' ' + oneOfTheTracks.user.last_name; } + if(isOpener) { + var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL); + } + // Default trackData to participant + no Mixer state. var trackData = { trackId: oneOfTheTracks.id, @@ -1346,14 +1363,14 @@ } trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; - trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) trackData.mediaControlsDisabled = !isOpener; trackData.mediaTrackOpener = isOpener; trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener; - _addRecordingTrack(trackData, mixer); + _addRecordingTrack(trackData, mixer, oppositeMixer); }); if(!noCorrespondingTracks && recordedTracks.length > 0) { @@ -1771,7 +1788,7 @@ - function _addRecordingTrack(trackData, mixer) { + function _addRecordingTrack(trackData, mixer, oppositeMixer) { var parentSelector = '#session-recordedtracks-container'; var $destination = $(parentSelector); @@ -1790,7 +1807,7 @@ if(trackData.mediaControlsDisabled) { $trackIconMute.data('media-controls-disabled', true).data('media-track-opener', trackData.mediaTrackOpener) } - $trackIconMute.data('mixer', mixer).data('opposite-mixer', null) + $trackIconMute.data('mixer', mixer).data('opposite-mixer', oppositeMixer) $trackIconMute.data('showHelpAboutMediaMixers', trackData.showHelpAboutMediaMixers) @@ -1823,6 +1840,7 @@ $.each(mixerIds, function(i,v) { var broadcast = !(data.dragging); // If fader is still dragging, don't broadcast var mixer = fillTrackVolumeObject(v, broadcast); + setMixerVolume(mixer, data.percentage); if(groupId == ChannelGroupIds.UserMusicInputGroup) { @@ -2039,12 +2057,14 @@ var mixer = $control.data('mixer'); var oppositeMixer = $control.data('opposite-mixer') - if(mixer && oppositeMixer && mixer.group_id == ChannelGroupIds.AudioInputMusicGroup) { + if(mixer && oppositeMixer && (mixer.group_id == ChannelGroupIds.AudioInputMusicGroup || mediaTrackGroups.indexOf(mixer.group_id) > -1)) { // this is the user's local track; mute both personal and master mode + logger.debug("muting both master and personal mode mixers") _toggleAudioMute(mixer.id, muting, getMixer(mixer.id).mode) - _toggleAudioMute(oppositeMixer.id, muting, getMixer(oppositeMixer.id).mode) + _toggleAudioMute(oppositeMixer.id, muting, getMixer(oppositeMixer.uniqueId || oppositeMixer.id).mode) } else { + logger.debug("muting mixer") _toggleAudioMute(mixer.id, muting, getMixer(mixer.id).mode) } @@ -2148,11 +2168,11 @@ context.jamClient.SessionSetMasterLocalMix(dbValue); // context.jamClient.SessionSetMasterLocalMix(sliderValue); } else { - var isMediaMixer = mediaTrackGroups.indexOf(mixer.group_id) > -1; + //var isMediaMixer = mediaTrackGroups.indexOf(mixer.group_id) > -1; // if this is a media file (Metronome, JamTrack, BackingTrack, RecordedTrack), then we only modify master - var mixMode = isMediaMixer ? MIX_MODES.MASTER : sessionModel.getMixMode(); - context.jamClient.SessionSetControlState(mixer.id, mixMode); + //var mixMode = isMediaMixer ? MIX_MODES.MASTER : sessionModel.getMixMode(); + context.jamClient.SessionSetControlState(mixer.id, mixer.mode); } } diff --git a/web/app/views/clients/_help.html.slim b/web/app/views/clients/_help.html.slim index 4fda8bda3..7fe11020b 100644 --- a/web/app/views/clients/_help.html.slim +++ b/web/app/views/clients/_help.html.slim @@ -201,7 +201,7 @@ script type="text/template" id="template-help-media-controls-disabled" script type="text/template" id="template-help-volume-media-mixers" - | Audio files only expose master mix controls, so any change here will also affect everyone in the session. + | Audio files only expose both master and personal mix controls, so any change here will also affect everyone in the session. script type="text/template" id="template-help-downloaded-jamtrack" .downloaded-jamtrack diff --git a/web/app/views/dialogs/_banner.html.slim b/web/app/views/dialogs/_banner.html.slim index 4083903e3..fe406d529 100644 --- a/web/app/views/dialogs/_banner.html.slim +++ b/web/app/views/dialogs/_banner.html.slim @@ -62,7 +62,7 @@ script type='text/template' id='template-mixer-mode-change' div The personal mix controls the audio mix that you individually hear while playing in the session, and you can customize this mix to hear more or less of the music stream from each other musician playing in the session. This does not affect the master mix used for recordings or broadcasts. With personal mix selected, when you adjust the faders on the session screen up or down, it changes the personal mix only for you locally. li span.definition Note on Audio Files - div The volume control on any audio file is always a master volume control, regardless of the current mode. + div The volume control on any audio file is always both the master and personal volume control, regardless of the current mode. br div | For more detailed information on this topic, read our knowledge base article on  From be4627d51fe507613058811ffd894f92acbc6b26 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 23 Feb 2015 15:55:02 -0600 Subject: [PATCH 12/22] * move around shopping cart init --- web/app/assets/javascripts/everywhere/everywhere.js | 10 ++++++++++ web/app/assets/javascripts/layout.js | 2 -- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/web/app/assets/javascripts/everywhere/everywhere.js b/web/app/assets/javascripts/everywhere/everywhere.js index f89aeacba..929bb2290 100644 --- a/web/app/assets/javascripts/everywhere/everywhere.js +++ b/web/app/assets/javascripts/everywhere/everywhere.js @@ -17,6 +17,7 @@ var ALERT_NAMES = context.JK.ALERT_NAMES; var logger = context.JK.logger; var stun = null; + var rest = context.JK.Rest(); $(document).on('JAMKAZAM_CONSTRUCTED', function(e, data) { @@ -207,4 +208,13 @@ } } + function initShoppingCart(app) { + var user = app.user() + if(user) { + user.done(function(userProfile) { + rest.getShoppingCarts().done(displayCartIcon) + }) + } + } + })(window, jQuery); diff --git a/web/app/assets/javascripts/layout.js b/web/app/assets/javascripts/layout.js index ab1c98813..09332ef0c 100644 --- a/web/app/assets/javascripts/layout.js +++ b/web/app/assets/javascripts/layout.js @@ -296,8 +296,6 @@ left: left + "px" }; $('[layout="header"]').css(css); - - rest.getShoppingCarts().done(displayCartIcon) } function layoutNotify(screenWidth, screenHeight) { From 78ed25ea826f53d1f2702495de10f663c7639a74 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 23 Feb 2015 16:00:30 -0600 Subject: [PATCH 13/22] * actually init the shopping cart --- web/app/assets/javascripts/everywhere/everywhere.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/app/assets/javascripts/everywhere/everywhere.js b/web/app/assets/javascripts/everywhere/everywhere.js index 929bb2290..fd0e49aef 100644 --- a/web/app/assets/javascripts/everywhere/everywhere.js +++ b/web/app/assets/javascripts/everywhere/everywhere.js @@ -52,6 +52,8 @@ operationalEvents(app); handleGettingStarted(app); + + initShoppingCart(app); }); function watchPreferencesEvent(app) { From 079579190988e8d21c5a10a5f9b1321985e4d6f2 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 23 Feb 2015 16:03:44 -0600 Subject: [PATCH 14/22] * move displayCartIcon method to init logic --- web/app/assets/javascripts/everywhere/everywhere.js | 10 ++++++++++ web/app/assets/javascripts/layout.js | 9 --------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/web/app/assets/javascripts/everywhere/everywhere.js b/web/app/assets/javascripts/everywhere/everywhere.js index fd0e49aef..c0c06c0ec 100644 --- a/web/app/assets/javascripts/everywhere/everywhere.js +++ b/web/app/assets/javascripts/everywhere/everywhere.js @@ -211,6 +211,16 @@ } function initShoppingCart(app) { + + function displayCartIcon(carts) { + var cartLink = $("a[href='" + "/client#/shoppingCart" + "']") + if (carts.length > 0) { + cartLink.removeClass("hidden") + } else { + cartLink.addClass("hidden") + } + } + var user = app.user() if(user) { user.done(function(userProfile) { diff --git a/web/app/assets/javascripts/layout.js b/web/app/assets/javascripts/layout.js index 09332ef0c..6c40f596d 100644 --- a/web/app/assets/javascripts/layout.js +++ b/web/app/assets/javascripts/layout.js @@ -275,15 +275,6 @@ $expandedPanelContents.animate({"height": expandedPanelHeight + "px"}, opts.animationDuration); } - function displayCartIcon(carts) { - var cartLink = $("a[href='" + "/client#/shoppingCart" + "']") - if (carts.length > 0) { - cartLink.removeClass("hidden") - } else { - cartLink.addClass("hidden") - } - } - function layoutHeader(screenWidth, screenHeight) { var width = screenWidth - 2 * opts.gutter; var height = opts.headerHeight - opts.gutter; From c5b77a02fa248ad59cb0659a7f8b1354bc60d3e7 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 23 Feb 2015 17:30:06 -0600 Subject: [PATCH 15/22] * check shopping cart on leave of shopping cart screen --- .../javascripts/everywhere/everywhere.js | 12 ++------ .../javascripts/jam_track_utils.js.coffee | 29 +++++++++++++++++++ web/app/assets/javascripts/shopping_cart.js | 8 ++++- 3 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 web/app/assets/javascripts/jam_track_utils.js.coffee diff --git a/web/app/assets/javascripts/everywhere/everywhere.js b/web/app/assets/javascripts/everywhere/everywhere.js index c0c06c0ec..4564cd9b0 100644 --- a/web/app/assets/javascripts/everywhere/everywhere.js +++ b/web/app/assets/javascripts/everywhere/everywhere.js @@ -7,6 +7,7 @@ //= require backend_alerts //= require stun //= require influxdb-latest +//= require jam_track_utils (function (context, $) { @@ -212,19 +213,10 @@ function initShoppingCart(app) { - function displayCartIcon(carts) { - var cartLink = $("a[href='" + "/client#/shoppingCart" + "']") - if (carts.length > 0) { - cartLink.removeClass("hidden") - } else { - cartLink.addClass("hidden") - } - } - var user = app.user() if(user) { user.done(function(userProfile) { - rest.getShoppingCarts().done(displayCartIcon) + context.JK.JamTrackUtils.checkShoppingCart(); }) } } diff --git a/web/app/assets/javascripts/jam_track_utils.js.coffee b/web/app/assets/javascripts/jam_track_utils.js.coffee new file mode 100644 index 000000000..2935665cc --- /dev/null +++ b/web/app/assets/javascripts/jam_track_utils.js.coffee @@ -0,0 +1,29 @@ + + +$ = jQuery +context = window +context.JK ||= {}; + +class JamTrackUtils + constructor: () -> + @logger = context.JK.logger + @rest = new context.JK.Rest(); + + init: () => + + # check if the shopping cart should be shown + checkShoppingCart: () => + @rest.getShoppingCarts().done(this.displayCartIcon) + + displayCartIcon: (carts) => + cartLink = $("a[href='" + "/client#/shoppingCart" + "']") + if carts.length > 0 + cartLink.removeClass("hidden") + else + cartLink.addClass("hidden") + + + + +# global instance +context.JK.JamTrackUtils = new JamTrackUtils() \ No newline at end of file diff --git a/web/app/assets/javascripts/shopping_cart.js b/web/app/assets/javascripts/shopping_cart.js index ac02b8b39..4a7d2bf7e 100644 --- a/web/app/assets/javascripts/shopping_cart.js +++ b/web/app/assets/javascripts/shopping_cart.js @@ -5,6 +5,7 @@ context.JK.ShoppingCartScreen = function(app) { var logger = context.JK.logger; + var jamTrackUtils = context.JK.JamTrackUtils; var $screen = null; var $content = null; @@ -16,6 +17,10 @@ function afterShow(data) { } + function afterHide() { + jamTrackUtils.checkShoppingCart(); + } + function events() { $screen.find("a.remove-cart").on('click', removeCart); $screen.find("a.proceed-checkout").on('click', proceedCheckout); @@ -94,7 +99,8 @@ function initialize() { var screenBindings = { 'beforeShow': beforeShow, - 'afterShow': afterShow + 'afterShow': afterShow, + 'afterHide' : afterHide }; app.bindScreen('shoppingCart', screenBindings); From a7824249a87c59d19d108591327679c95646db83 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Mon, 23 Feb 2015 22:29:28 -0600 Subject: [PATCH 16/22] * VRFS-2826 - fix regression where remote peers couldn't see tracks --- web/app/assets/javascripts/session.js | 29 ++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index d91ebf0d5..9aff18f4b 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -1027,7 +1027,12 @@ if(isOpener) { var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL); + var mixerId = mixer.id + "," + oppositeMixer.uniqueId } + else { + var mixerId = mixer.id; + } + var shortFilename = context.JK.getNameOfFile(backingTrack.filename); if(!sessionModel.isPlayingRecording()) { @@ -1067,7 +1072,7 @@ trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; - trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.mixerId = mixerId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) trackData.mediaTrackOpener = isOpener; @@ -1132,7 +1137,12 @@ if(isOpener) { var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL); + var mixerId = mixer.id + "," + oppositeMixer.uniqueId } + else { + var mixerId = mixer.id; + } + // Default trackData to participant + no Mixer state. var trackData = { trackId: oneOfTheTracks.id, @@ -1156,7 +1166,7 @@ } trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; - trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.mixerId = mixerId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) trackData.mediaTrackOpener = isOpener; @@ -1235,8 +1245,13 @@ if(isOpener) { var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL); + var mixerId = mixer.id + "," + oppositeMixer.uniqueId } - + else { + var mixerId = mixer.id; + } + + // Default trackData to participant + no Mixer state. var trackData = { trackId: "MS" + oneOfTheTracks.id, @@ -1261,7 +1276,7 @@ } trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; - trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.mixerId = mixerId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) trackData.mediaTrackOpener = isOpener; @@ -1338,6 +1353,10 @@ if(isOpener) { var oppositeMixer = getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL); + var mixerId = mixer.id + "," + oppositeMixer.uniqueId + } + else { + var mixerId = mixer.id; } // Default trackData to participant + no Mixer state. @@ -1363,7 +1382,7 @@ } trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; - trackData.mixerId = mixer.id + "," + oppositeMixer.uniqueId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) + trackData.mixerId = mixerId; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) trackData.mediaControlsDisabled = !isOpener; From 947d649f5ff9f4ece754a8e0d98474cb4db5bdf5 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Tue, 24 Feb 2015 17:16:12 -0600 Subject: [PATCH 17/22] * VRFS-2831 - metronome showing --- db/up/recorded_jam_track_tracks.sql | 15 +++++++++ .../models/recorded_jam_track_track.rb | 21 ++++++++++++ web/app/assets/javascripts/session.js | 33 ++++++++++++------- 3 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 db/up/recorded_jam_track_tracks.sql create mode 100644 ruby/lib/jam_ruby/models/recorded_jam_track_track.rb diff --git a/db/up/recorded_jam_track_tracks.sql b/db/up/recorded_jam_track_tracks.sql new file mode 100644 index 000000000..246b76425 --- /dev/null +++ b/db/up/recorded_jam_track_tracks.sql @@ -0,0 +1,15 @@ +ALTER TABLE recordings ADD COLUMN jam_track_id VARCHAR(64) REFERENCES jam_tracks(id); +ALTER TABLE recordings ADD COLUMN jam_track_initiator_id VARCHAR(64) REFERENCES users(id); + +CREATE TABLE recorded_jam_track_tracks ( + id BIGINT PRIMARY KEY, + user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE, + jam_track_track_id VARCHAR(64), + recording_id VARCHAR(64) NOT NULL, + discard BOOLEAN, + timeline JSON, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +ALTER TABLE recorded_jam_tracks ALTER COLUMN id SET DEFAULT nextval('tracks_next_tracker_seq'); \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/recorded_jam_track_track.rb b/ruby/lib/jam_ruby/models/recorded_jam_track_track.rb new file mode 100644 index 000000000..19907eb1c --- /dev/null +++ b/ruby/lib/jam_ruby/models/recorded_jam_track_track.rb @@ -0,0 +1,21 @@ +module JamRuby + # BackingTrack analog to JamRuby::RecordedTrack + class RecordedJamTrackTrack < ActiveRecord::Base + + belongs_to :user, :class_name => "JamRuby::User", :inverse_of => :recorded_jam_track_tracks + belongs_to :recording, :class_name => "JamRuby::Recording", :inverse_of => :recorded_jam_track_tracks + belongs_to :jam_track_track, :class_name => "JamRuby::JamTrackTrack", :inverse_of => :recorded_jam_track_tracks + + validates :user, presence: true + validates :jam_track_track, presence:true + + def self.create_from_jam_track_track(jam_track_track, recording) + recorded_backing_track = self.new + recorded_backing_track.recording = recording + recorded_backing_track.jam_track_track = jam_track_track + recorded_backing_track.save + recorded_backing_track + end + + end +end diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 9aff18f4b..183a94e81 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -890,8 +890,11 @@ var mediaType = mixer.media_type; var groupId = mixer.group_id; - // mediaType == null is for backwards compat with older clients. Can be removed soon - if(mediaType == null || mediaType == "" || mediaType == 'RecordingTrack') { + if(mediaType == 'MetronomeTrack' || groupId==ChannelGroupIds.MetronomeGroup) { + // Metronomes come across with a blank media type, so check group_id: + metronomeTrackMixers.push(mixer); + } + else if(mediaType == null || mediaType == "" || mediaType == 'RecordingTrack') { // additional check; if we can match an id in backing tracks or recorded backing track, // we need to remove it from the recorded track set, but move it to the backing track set @@ -922,9 +925,6 @@ } else if(mediaType == 'PeerMediaTrack' || mediaType == 'BackingTrack') { // BackingTrack backingTrackMixers.push(mixer); - } else if(mediaType == 'MetronomeTrack' || groupId==ChannelGroupIds.MetronomeGroup) { - // Metronomes come across with a blank media type, so check group_id: - metronomeTrackMixers.push(mixer); } else if(mediaType == 'JamTrack') { jamTrackMixers.push(mixer); mixer.group_id == ChannelGroupIds.MediaTrackGroup; @@ -1980,11 +1980,22 @@ rest.openBackingTrack({id: context.JK.CurrentSessionModel.id(), backing_track_path: result.file}) .done(function(response) { var openResult = context.jamClient.SessionOpenBackingTrackFile(result.file, false); - //context.JK.CurrentSessionModel.refreshCurrentSession(true); - sessionModel.setBackingTrack(result.file); + + if(openResult) { + sessionModel.setBackingTrack(result.file); + } + else { + app.notify({ + "title": "Couldn't Open Backing Track", + "text": "Is the file a valid audio file?", + "icon_url": "/assets/content/icon_alert_big.png" + }); + closeBackingTrack(); + } + }) .fail(function(jqXHR) { - app.notifyServerError(jqXHR, "Unable to Open BackingTrack For Playback"); + app.notifyServerError(jqXHR, "Unable to Open Backing Track For Playback"); }) } else { @@ -2443,8 +2454,6 @@ rest.openMetronome({id: sessionModel.id()}) .done(function() { context.jamClient.SessionOpenMetronome(120, "Click", 1, 0) - context.JK.CurrentSessionModel.refreshCurrentSession(true) - context.JK.CurrentSessionModel.refreshCurrentSession(true) }) .fail(function(jqXHR) { logger.debug(jqXHR, jqXHR) @@ -2506,8 +2515,8 @@ }) .fail(function(jqXHR) { app.notify({ - "title": "Couldn't Close BackingTrack", - "text": "Couldn't inform the server to close BackingTrack. msg=" + jqXHR.responseText, + "title": "Couldn't Close Backing Track", + "text": "Couldn't inform the server to close Backing Track. msg=" + jqXHR.responseText, "icon_url": "/assets/content/icon_alert_big.png" }); }); From 6b795695eea28070bf28aa7984dd2265f940be31 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Wed, 25 Feb 2015 16:15:41 -0600 Subject: [PATCH 18/22] * VRFS-2753 - assign volume left over volume right to ensure both mono and stereo backend inputs get the data they need --- web/app/assets/javascripts/session.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 183a94e81..b47946641 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -2140,7 +2140,11 @@ context.trackVolumeObject.name = mixer.name; context.trackVolumeObject.record = mixer.record; context.trackVolumeObject.volL = mixer.volume_left; - context.trackVolumeObject.volR = mixer.volume_right; + + // today we treat all tracks as mono, but this is required to make a stereo track happy + //context.trackVolumeObject.volR = mixer.volume_right; + context.trackVolumeObject.volR = mixer.volume_left; + context.trackVolumeObject.loop = mixer.loop; // trackVolumeObject doesn't have a place for range min/max currentMixerRangeMin = mixer.range_low; From 471f590ef78307d903fb027f7260b6579ac95025 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Wed, 25 Feb 2015 19:57:01 -0600 Subject: [PATCH 19/22] * update doc of teaspoon tests; really just a fake bump for dev build --- web/README.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/web/README.md b/web/README.md index b32f3ab99..f2dccf0a1 100644 --- a/web/README.md +++ b/web/README.md @@ -1,10 +1,4 @@ Jasmine Javascript Unit Tests ============================= -1. Ensure you have the jasmine Gem installed; -$ bundle - -2. Start the jasmine server (defaults to :8888) -$ rake jasmine - -Open browser to localhost:8888 +Open browser to localhost:3000/teaspoon From 6107622f79f8c0fef9a5f6a9be4ef3b38b07cf1c Mon Sep 17 00:00:00 2001 From: Seth Call Date: Wed, 25 Feb 2015 22:04:58 -0600 Subject: [PATCH 20/22] * VRFS-2839 - add check to admin --- admin/app/controllers/checks_controller.rb | 19 +++++++++++++++++++ admin/config/routes.rb | 1 + 2 files changed, 20 insertions(+) create mode 100644 admin/app/controllers/checks_controller.rb diff --git a/admin/app/controllers/checks_controller.rb b/admin/app/controllers/checks_controller.rb new file mode 100644 index 000000000..52330c2aa --- /dev/null +++ b/admin/app/controllers/checks_controller.rb @@ -0,0 +1,19 @@ +class ChecksController < ApplicationController + + #respond_to :json + + # create or update a client_artifact row + def check_latency_tester + + latency_tester_name = params[:name] + + exists = Connection.where(client_type: Connection::TYPE_LATENCY_TESTER).where(client_id: latency_tester_name).first + + if exists + render :text => "", :status => :ok + else + render :text => "", :status => 404 + end + end + +end \ No newline at end of file diff --git a/admin/config/routes.rb b/admin/config/routes.rb index 05aed06bc..bae57c044 100644 --- a/admin/config/routes.rb +++ b/admin/config/routes.rb @@ -32,6 +32,7 @@ JamAdmin::Application.routes.draw do match '/api/artifacts' => 'artifacts#update_artifacts', :via => :post match '/api/mix/:id/enqueue' => 'admin/mixes#mix_again', :via => :post + match '/api/checks/latency_tester' => 'checks#check_latency_tester', :via => :get mount Resque::Server.new, :at => "/resque" From 671151b460c6ac619a3d3aac394710f75a61ea2a Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 26 Feb 2015 10:00:21 -0600 Subject: [PATCH 21/22] * VRFS-2804 - widen authorization token --- db/manifest | 3 ++- db/up/widen_user_authohrization_token.sql | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 db/up/widen_user_authohrization_token.sql diff --git a/db/manifest b/db/manifest index 55f1373b5..96d0555ba 100755 --- a/db/manifest +++ b/db/manifest @@ -252,4 +252,5 @@ metronome.sql recorded_backing_tracks.sql recorded_backing_tracks_add_filename.sql user_syncs_include_backing_tracks.sql -remove_bpm_from_jamtracks.sql \ No newline at end of file +remove_bpm_from_jamtracks.sql +widen_user_authorization_token.sql \ No newline at end of file diff --git a/db/up/widen_user_authohrization_token.sql b/db/up/widen_user_authohrization_token.sql new file mode 100644 index 000000000..070f67b83 --- /dev/null +++ b/db/up/widen_user_authohrization_token.sql @@ -0,0 +1 @@ +alter table user_authorizations ALTER COLUMN token TYPE character varying(2000); \ No newline at end of file From 3abe9108cddfd7bb02cc573a6751be613eee2829 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 26 Feb 2015 10:04:59 -0600 Subject: [PATCH 22/22] * fix typo --- ...uthohrization_token.sql => widen_user_authorization_token.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename db/up/{widen_user_authohrization_token.sql => widen_user_authorization_token.sql} (100%) diff --git a/db/up/widen_user_authohrization_token.sql b/db/up/widen_user_authorization_token.sql similarity index 100% rename from db/up/widen_user_authohrization_token.sql rename to db/up/widen_user_authorization_token.sql