This commit is contained in:
Seth Call 2015-02-27 08:41:49 -06:00
commit 9415593244
25 changed files with 352 additions and 65 deletions

View File

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

View File

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

View File

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

View File

@ -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');

View File

@ -0,0 +1 @@
alter table user_authorizations ALTER COLUMN token TYPE character varying(2000);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
})
}

View File

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

View File

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

View File

@ -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();

View File

@ -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();

View File

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

View File

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

View File

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

View File

@ -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
= "{% }; %}"

View File

@ -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&nbsp;

View File

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

View File

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

View File

@ -54,6 +54,7 @@ gem 'language_list'
gem 'rubyzip'
gem 'sanitize'
gem 'influxdb', '0.1.8'
gem 'recurly'
group :development do
gem 'pry'