* merged
This commit is contained in:
commit
9415593244
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -253,6 +253,7 @@ recorded_backing_tracks.sql
|
|||
recorded_backing_tracks_add_filename.sql
|
||||
user_syncs_include_backing_tracks.sql
|
||||
remove_bpm_from_jamtracks.sql
|
||||
widen_user_authorization_token.sql
|
||||
jam_track_version.sql
|
||||
recorded_jam_track_tracks.sql
|
||||
jam_track_jmep_data.sql
|
||||
jam_track_jmep_data.sql
|
||||
|
|
|
|||
|
|
@ -12,4 +12,4 @@ CREATE TABLE recorded_jam_track_tracks (
|
|||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE recorded_jam_track_tracks ALTER COLUMN id SET DEFAULT nextval('tracks_next_tracker_seq');
|
||||
ALTER TABLE recorded_jam_track_tracks ALTER COLUMN id SET DEFAULT nextval('tracks_next_tracker_seq');
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
alter table user_authorizations ALTER COLUMN token TYPE character varying(2000);
|
||||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,18 @@
|
|||
# initialize actionmailer
|
||||
ActionMailer::Base.raise_delivery_errors = true
|
||||
ActionMailer::Base.view_paths = File.expand_path('../../jam_ruby/app/views/', __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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -68,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)
|
||||
jam_track_right = nil
|
||||
account = get_account(current_user)
|
||||
|
|
@ -739,6 +739,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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
//= require backend_alerts
|
||||
//= require stun
|
||||
//= require influxdb-latest
|
||||
//= require jam_track_utils
|
||||
|
||||
(function (context, $) {
|
||||
|
||||
|
|
@ -17,6 +18,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) {
|
||||
|
||||
|
|
@ -51,6 +53,8 @@
|
|||
operationalEvents(app);
|
||||
|
||||
handleGettingStarted(app);
|
||||
|
||||
initShoppingCart(app);
|
||||
});
|
||||
|
||||
function watchPreferencesEvent(app) {
|
||||
|
|
@ -207,4 +211,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
function initShoppingCart(app) {
|
||||
|
||||
var user = app.user()
|
||||
if(user) {
|
||||
user.done(function(userProfile) {
|
||||
context.JK.JamTrackUtils.checkShoppingCart();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
})(window, jQuery);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
var duration = context.jamClient.SessionGetJamTracksPlayDurationMs();
|
||||
var durationMs = duration.media_len;
|
||||
var start = duration.start; // needed to understand start offset, and prevent slider from moving in tapins
|
||||
console.log("JamTrack start: " + start)
|
||||
//console.log("JamTrack start: " + start)
|
||||
}
|
||||
else {
|
||||
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@
|
|||
var $liveTracksContainer = null;
|
||||
var downloadJamTrack = null;
|
||||
var $closePlaybackRecording = null;
|
||||
var $openBackingTrack = null;
|
||||
var mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
|
||||
var rest = context.JK.Rest();
|
||||
|
|
@ -144,6 +145,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.');
|
||||
|
|
@ -618,7 +621,6 @@
|
|||
function _updateMixers() {
|
||||
masterMixers = context.jamClient.SessionGetAllControlState(true);
|
||||
personalMixers = context.jamClient.SessionGetAllControlState(false);
|
||||
context.jamClient
|
||||
|
||||
//logger.debug("masterMixers", masterMixers)
|
||||
//logger.debug("personalMixers", personalMixers)
|
||||
|
|
@ -642,10 +644,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
|
||||
|
||||
|
|
@ -926,8 +933,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
|
||||
|
||||
|
|
@ -958,9 +968,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;
|
||||
|
|
@ -1061,6 +1068,14 @@
|
|||
// 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 mixerId = mixer.id + "," + oppositeMixer.uniqueId
|
||||
}
|
||||
else {
|
||||
var mixerId = mixer.id;
|
||||
}
|
||||
|
||||
var shortFilename = context.JK.getNameOfFile(backingTrack.filename);
|
||||
|
||||
if(!sessionModel.isPlayingRecording()) {
|
||||
|
|
@ -1086,6 +1101,7 @@
|
|||
gainPercent: 0,
|
||||
muteClass: 'muted',
|
||||
showLoop: isOpener && !sessionModel.isPlayingRecording(),
|
||||
loopState: mixer.loop,
|
||||
mixerId: "",
|
||||
avatarClass: 'avatar-recording',
|
||||
preMasteredClass: ""
|
||||
|
|
@ -1100,14 +1116,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 = 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;
|
||||
trackData.mediaControlsDisabled = !isOpener;
|
||||
trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener;
|
||||
|
||||
_addRecordingTrack(trackData, mixer);
|
||||
_addRecordingTrack(trackData, mixer, oppositeMixer);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1158,6 +1174,14 @@
|
|||
name = oneOfTheTracks.instrument;
|
||||
}
|
||||
|
||||
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 = {
|
||||
type: 'jam_track',
|
||||
|
|
@ -1182,14 +1206,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 = 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;
|
||||
trackData.mediaControlsDisabled = !isOpener;
|
||||
trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener;
|
||||
|
||||
_addRecordingTrack(trackData);
|
||||
_addRecordingTrack(trackData, mixer, oppositeMixer);
|
||||
});
|
||||
|
||||
if(!noCorrespondingTracks && jamTracks.length > 0) {
|
||||
|
|
@ -1259,7 +1283,15 @@
|
|||
|
||||
// _addRecordingTrack(trackData);
|
||||
|
||||
|
||||
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 = {
|
||||
type: 'metronome',
|
||||
|
|
@ -1285,7 +1317,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 = 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;
|
||||
|
|
@ -1293,7 +1325,7 @@
|
|||
trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener;
|
||||
|
||||
|
||||
_addRecordingTrack(trackData, mixer);
|
||||
_addRecordingTrack(trackData, mixer, oppositeMixer);
|
||||
}// if
|
||||
setFormFromMetronome()
|
||||
}
|
||||
|
|
@ -1360,6 +1392,14 @@
|
|||
name = oneOfTheTracks.user.first_name + ' ' + oneOfTheTracks.user.last_name;
|
||||
}
|
||||
|
||||
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 = {
|
||||
type: 'recorded_track',
|
||||
|
|
@ -1384,14 +1424,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 = 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;
|
||||
trackData.mediaTrackOpener = isOpener;
|
||||
trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener;
|
||||
|
||||
_addRecordingTrack(trackData, mixer);
|
||||
_addRecordingTrack(trackData, mixer, oppositeMixer);
|
||||
});
|
||||
|
||||
if(!noCorrespondingTracks && recordedTracks.length > 0) {
|
||||
|
|
@ -1812,7 +1852,7 @@
|
|||
$('.session-recording-name-wrapper').show();
|
||||
}
|
||||
|
||||
function _addRecordingTrack(trackData, mixer) {
|
||||
function _addRecordingTrack(trackData, mixer, oppositeMixer) {
|
||||
|
||||
otherAudioFilled();
|
||||
|
||||
|
|
@ -1837,13 +1877,14 @@
|
|||
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)
|
||||
|
||||
|
||||
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() {
|
||||
|
|
@ -1869,6 +1910,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) {
|
||||
|
|
@ -1976,20 +2018,36 @@
|
|||
}
|
||||
|
||||
function handleBackingTrackSelectedCallback(result) {
|
||||
|
||||
$openBackingTrack.removeClass('disabled');
|
||||
|
||||
if(!sessionModel.inSession()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(result.success) {
|
||||
logger.debug("backing track selected: " + result.file);
|
||||
|
||||
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 {
|
||||
logger.debug("no backing track selected")
|
||||
|
|
@ -2087,12 +2145,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)
|
||||
}
|
||||
|
||||
|
|
@ -2138,7 +2198,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;
|
||||
|
|
@ -2196,11 +2260,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2352,6 +2416,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({
|
||||
|
|
@ -2362,13 +2432,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;
|
||||
}
|
||||
|
||||
|
|
@ -2451,6 +2516,7 @@
|
|||
}
|
||||
|
||||
function openBackingTrackFile(e) {
|
||||
|
||||
// just ignore the click if they are currently recording for now
|
||||
if(sessionModel.recordingModel.isRecording()) {
|
||||
app.notify({
|
||||
|
|
@ -2520,8 +2586,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)
|
||||
|
|
@ -2583,13 +2647,14 @@
|
|||
})
|
||||
.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"
|
||||
});
|
||||
});
|
||||
|
||||
// '' closes all open backing tracks
|
||||
context.jamClient.SessionStopPlay();
|
||||
context.jamClient.SessionCloseBackingTrackFile('');
|
||||
|
||||
return false;
|
||||
|
|
@ -2773,7 +2838,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);
|
||||
|
|
@ -2821,6 +2886,7 @@
|
|||
$myTracksContainer = $('#session-mytracks-container')
|
||||
$liveTracksContainer = $('#session-livetracks-container');
|
||||
$closePlaybackRecording = $('#close-playback-recording')
|
||||
$openBackingTrack = $('#open-a-backingtrack');
|
||||
events();
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ script type="text/template" id="template-help-jamtrack-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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
= "{% }; %}"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ gem 'language_list'
|
|||
gem 'rubyzip'
|
||||
gem 'sanitize'
|
||||
gem 'influxdb', '0.1.8'
|
||||
gem 'recurly'
|
||||
|
||||
group :development do
|
||||
gem 'pry'
|
||||
|
|
|
|||
Loading…
Reference in New Issue