* VRFS-3118 - check for high latency while in session, VRFS-3138 - fix tons of issues with user downloading both sample rates

This commit is contained in:
Seth Call 2015-05-01 12:09:18 -05:00
parent 487736a619
commit 1cd57cb4e8
27 changed files with 523 additions and 348 deletions

View File

@ -280,3 +280,4 @@ signup_hints.sql
packaging_notices.sql
first_played_jamtrack_at.sql
payment_history.sql
jam_track_right_private_key.sql

View File

@ -0,0 +1,11 @@
ALTER TABLE jam_track_rights ADD COLUMN private_key_44 VARCHAR;
ALTER TABLE jam_track_rights ADD COLUMN private_key_48 VARCHAR;
ALTER TABLE jam_track_rights ADD COLUMN signed_48 BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE jam_track_rights ADD COLUMN signed_44 BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE jam_track_rights DROP COLUMN private_key;
ALTER TABLE jam_track_rights DROP COLUMN signed;
ALTER TABLE jam_track_rights ADD COLUMN signing_started_at_44 TIMESTAMP;
ALTER TABLE jam_track_rights ADD COLUMN signing_started_at_48 TIMESTAMP;
ALTER TABLE jam_track_rights DROP COLUMN signing_started_at;

View File

@ -23,6 +23,6 @@ class JamTrackRightUploader < CarrierWave::Uploader::Base
end
def filename
"#{model.store_dir}/#{model.filename}" if model.id
"#{model.store_dir}/#{model.filename(mounted_as)}" if model.id
end
end

View File

@ -82,10 +82,18 @@ module JamRuby
else
jam_track_right.url_44.store!(File.open(output_jkz, "rb"))
end
jam_track_right.signed=true
jam_track_right.downloaded_since_sign=false
jam_track_right.private_key=File.read("#{tmp_dir}/skey.pem")
if sample_rate == 48
jam_track_right.signed_48 = true
jam_track_right.private_key_48 = File.read("#{tmp_dir}/skey.pem")
else
jam_track_right.signed_44 = true
jam_track_right.private_key_44 = File.read("#{tmp_dir}/skey.pem")
end
jam_track_right.signing_queued_at = nil # if left set, throws off signing_state on subsequent signing attempts
jam_track_right.downloaded_since_sign = false
jam_track_right.save!
end
end # mktmpdir

View File

@ -29,7 +29,7 @@ module JamRuby
# try to catch major transitions:
# if just queue time changes, start time changes, or signed time changes, send out a notice
if signing_queued_at_was != signing_queued_at || signing_started_at_was != signing_started_at || last_signed_at_was != last_signed_at || current_packaging_step != current_packaging_step_was || packaging_steps != packaging_steps_was
if signing_queued_at_was != signing_queued_at || signing_started_at_48_was != signing_started_at_48 || signing_started_at_44_was != signing_started_at_44 || last_signed_at_was != last_signed_at || current_packaging_step != current_packaging_step_was || packaging_steps != packaging_steps_was
SubscriptionMessage.jam_track_signing_job_change(self)
end
end
@ -39,8 +39,8 @@ module JamRuby
end
# create name of the file
def filename
"#{jam_track.name}.jkz"
def filename(bitrate)
"#{jam_track.name}-#{bitrate == :url_48 ? '48' : '44'}.jkz"
end
def verify_download_count
@ -71,11 +71,12 @@ module JamRuby
if bitrate==48
self.length_48 = length
self.md5_48 = md5
self.signed_48 = true
else
self.length_44 = length
self.md5_44 = md5
self.signed_44 = true
end
self.signed = true
self.error_count = 0
self.error_reason = nil
self.error_detail = nil
@ -104,7 +105,7 @@ module JamRuby
def enqueue(sample_rate=48)
begin
JamTrackRight.where(:id => self.id).update_all(:signing_queued_at => Time.now, :signing_started_at => nil, :last_signed_at => nil)
JamTrackRight.where(:id => self.id).update_all(:signing_queued_at => Time.now, :signing_started_at_44 => nil, :signing_started_at_48 => nil, :last_signed_at => nil)
Resque.enqueue(JamTracksBuilder, self.id, sample_rate)
true
rescue Exception => e
@ -116,7 +117,7 @@ module JamRuby
# if the job is already signed, just queued up for signing, or currently signing, then don't enqueue... otherwise fire it off
def enqueue_if_needed(sample_rate=48)
state = signing_state
state = signing_state(sample_rate)
if state == 'SIGNED' || state == 'SIGNING' || state == 'QUEUED'
false
else
@ -129,9 +130,9 @@ module JamRuby
# @return true if signed && file exists for the sample_rate specifed:
def ready?(sample_rate=48)
if sample_rate==48
self.signed && self.url_48.present? && self.url_48.file.exists?
self.signed_48 && self.url_48.present? && self.url_48.file.exists?
else
self.signed && self.url_44.present? && self.url_44.file.exists?
self.signed_44 && self.url_44.present? && self.url_44.file.exists?
end
end
@ -143,8 +144,20 @@ module JamRuby
# QUEUED_TIMEOUT - the package signing job (JamTrackBuilder) was queued, but never executed
# QUEUED - the package is queued to sign
# QUIET - the jam_track_right exists, but no job has been kicked off; a job needs to be enqueued
def signing_state
def signing_state(sample_rate = nil)
state = nil
# if the caller did not specified sample rate, we will determine what signing state to check by looking at the most recent signing attempt
if sample_rate.nil?
# determine what package is being signed by checking the most recent signing_started at
time_48 = signing_started_at_48.to_i
time_44 = signing_started_at_44.to_i
sample_rate = time_48 > time_44 ? 48 : 44
end
signed = sample_rate == 48 ? signed_48 : signed_44
signing_started_at = sample_rate == 48 ? signing_started_at_48 : signing_started_at_44
if signed
state = 'SIGNED'
elsif signing_started_at
@ -170,11 +183,16 @@ module JamRuby
end
state
end
def signed?(sample_rate)
sample_rate == 48 ? signed_48 : signed_44
end
def update_download_count(count=1)
self.download_count = self.download_count + count
self.last_downloaded_at = Time.now
if self.signed
if self.signed_44 || self.signed_48
self.downloaded_since_sign = true
end
end
@ -184,7 +202,7 @@ module JamRuby
return []
end
JamTrack.select('jam_tracks.id, jam_track_rights.private_key AS private_key, jam_track_rights.id AS jam_track_right_id')
JamTrack.select('jam_tracks.id, jam_track_rights.private_key_44 AS private_key_44, jam_track_rights.private_key_48 AS private_key_48, jam_track_rights.id AS jam_track_right_id')
.joins("LEFT OUTER JOIN jam_track_rights ON jam_tracks.id = jam_track_rights.jam_track_id AND jam_track_rights.user_id = '#{user.id}'")
.where('jam_tracks.id IN (?)', jamtracks)
end

View File

@ -29,7 +29,7 @@ module JamRuby
@jam_track_right = JamTrackRight.find(jam_track_right_id)
# bailout check
if @jam_track_right.signed
if @jam_track_right.signed?(bitrate)
log.debug("package is already signed. bailing")
return
end
@ -39,12 +39,13 @@ module JamRuby
# track that it's started ( and avoid db validations )
signing_started_at = Time.now
signing_started_model_symbol = bitrate == 48 ? :signing_started_at_48 : :signing_started_at_44
last_step_at = Time.now
JamTrackRight.where(:id => @jam_track_right.id).update_all(:signing_started_at => signing_started_at, :should_retry => false, packaging_steps: total_steps, current_packaging_step: 0, last_step_at: last_step_at)
# because we are skiping after_save, we have to keep the model current for the notification. A bit ugly...
JamTrackRight.where(:id => @jam_track_right.id).update_all(signing_started_model_symbol => signing_started_at, :should_retry => false, packaging_steps: total_steps, current_packaging_step: 0, last_step_at: last_step_at)
# because we are skipping 'after_save', we have to keep the model current for the notification. A bit ugly...
@jam_track_right.current_packaging_step = 0
@jam_track_right.packaging_steps = total_steps
@jam_track_right.signing_started_at = signing_started_at
@jam_track_right[signing_started_model_symbol] = signing_started_at
@jam_track_right.should_retry = false
@jam_track_right.last_step_at = Time.now
SubscriptionMessage.jam_track_signing_job_change(@jam_track_right)

View File

@ -76,7 +76,7 @@ describe JamTrackRight do
JamRuby::JamTracksManager.save_jam_track_jkz(user, jam_track)
#}.to_not raise_error(ArgumentError)
jam_track_right.reload
jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename
jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename(:url_48)
# verify it's on S3
url = jam_track_right[:url_48]
@ -109,11 +109,12 @@ describe JamTrackRight do
end
it "valid track with rights to it by querying user" do
jam_track_right = FactoryGirl.create(:jam_track_right, private_key: 'keyabc')
jam_track_right = FactoryGirl.create(:jam_track_right, private_key_44: 'keyabc')
keys = JamTrackRight.list_keys(jam_track_right.user, [jam_track_right.jam_track.id])
keys.should have(1).items
keys[0].id.should == jam_track_right.jam_track.id
keys[0]['private_key'].should eq('keyabc')
keys[0]['private_key_44'].should eq('keyabc')
keys[0]['private_key_48'].should be_nil
end
end
@ -124,7 +125,7 @@ describe JamTrackRight do
end
it "signed" do
right = FactoryGirl.create(:jam_track_right, signed: true)
right = FactoryGirl.create(:jam_track_right, signed_44: true, signing_started_at_44: Time.now)
right.signing_state.should eq('SIGNED')
end
@ -134,23 +135,23 @@ describe JamTrackRight do
end
it "signing" do
right = FactoryGirl.create(:jam_track_right, signing_started_at: Time.now, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now)
right.signing_state.should eq('SIGNING')
right = FactoryGirl.create(:jam_track_right, signing_started_at_44: Time.now, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now)
right.signing_state(44).should eq('SIGNING')
end
it "signing timeout" do
right = FactoryGirl.create(:jam_track_right, signing_started_at: Time.now - 100, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now)
right.signing_state.should eq('SIGNING_TIMEOUT')
right = FactoryGirl.create(:jam_track_right, signing_started_at_48: Time.now - 100, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now)
right.signing_state(48).should eq('SIGNING_TIMEOUT')
end
it "queued" do
right = FactoryGirl.create(:jam_track_right, signing_queued_at: Time.now)
right.signing_state.should eq('QUEUED')
right.signing_state(44).should eq('QUEUED')
end
it "signing timeout" do
right = FactoryGirl.create(:jam_track_right, signing_queued_at: Time.now - (APP_CONFIG.signing_job_queue_max_time + 1))
right.signing_state.should eq('QUEUED_TIMEOUT')
right.signing_state(44).should eq('QUEUED_TIMEOUT')
end
end

View File

@ -44,8 +44,13 @@ describe JamTracksBuilder do
jam_track_right[:url_44].should be_nil
JamTracksBuilder.perform(jam_track_right.id, 48)
jam_track_right.reload
jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename
jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename(:url_48)
jam_track_track[:url_44].should be_nil
jam_track_right.signed_48.should be_true
jam_track_right.signing_started_at_48.should_not be_nil
jam_track_right.signed_44.should be_false
jam_track_right.signing_started_at_44.should be_nil
end
describe "with bitrate 44" do
@ -76,9 +81,14 @@ describe JamTracksBuilder do
jam_track_right[:url_48].should be_nil
JamTracksBuilder.perform(jam_track_right.id, 44)
jam_track_right.reload
jam_track_right[:url_44].should == jam_track_right.store_dir + '/' + jam_track_right.filename
jam_track_right[:url_44].should == jam_track_right.store_dir + '/' + jam_track_right.filename(:url_44)
jam_track_right.url_44.should_not be_nil
jam_track_track[:url_48].should be_nil
jam_track_right.signed_44.should be_true
jam_track_right.signing_started_at_44.should_not be_nil
jam_track_right.signed_48.should be_false
jam_track_right.signing_started_at_48.should be_nil
end
end
end

View File

@ -23,14 +23,14 @@ describe JamTracksCleaner do
it "should clean" do
jam_track_right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
jam_track_right.signed=true
jam_track_right.signed_48=true
jam_track_right
jam_track_right.url_48.store!(File.open(RIGHT_NAME))
jam_track_right.downloaded_since_sign=true
jam_track_right.save!
jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename
jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename(:url_48)
jam_track_right.reload
# Should exist after uploading:

View File

@ -69,7 +69,10 @@
logger.debug("alert callback", type, text);
var alertData = ALERT_TYPES[type];
var alertData = $.extend({}, ALERT_TYPES[type]);
alertData.text = text;
if(alertData) {
$document.triggerHandler(alertData.name, alertData);
}

View File

@ -13,6 +13,8 @@
var $templateOpenJamTrackRow = null;
var $downloadedTrackHelp = null;
var $whatAreJamTracks = null;
var sampleRate = null;
var sampleRateForFilename = null;
function emptyList() {
@ -24,18 +26,25 @@
}
function beforeShow() {
}
function afterShow() {
$dialog.data('result', null)
emptyList();
resetPagination();
showing = true;
sampleRate = context.jamClient.GetSampleRate()
sampleRateForFilename = sampleRate == 48 ? '48' : '44';
getPurchasedJamTracks(0)
.done(function(data, textStatus, jqXHR) {
// initialize pagination
var $paginator = context.JK.Paginator.create(parseInt(jqXHR.getResponseHeader('total-entries')), perPage, 0, onPageSelected)
$paginatorHolder.append($paginator);
});
}
}
function afterHide() {
showing = false;
}
@ -58,7 +67,7 @@
options.jamTrackId = jamTrack.id;
options.name = jamTrack.name;
options.artist = jamTrack.original_artist;
var detail = context.jamClient.JamTrackGetTrackDetail(jamTrack.id) || {}
var detail = context.jamClient.JamTrackGetTrackDetail(jamTrack.id + '-' + sampleRateForFilename) || {}
options.downloaded = detail.key_state == 'ready' ? 'Yes' : 'No'
var $tr = $(context._.template($templateOpenJamTrackRow.html(), options, { variable: 'data' }));
@ -99,6 +108,7 @@
function initialize(){
var dialogBindings = {
'beforeShow' : beforeShow,
'afterShow' : afterShow,
'afterHide': afterHide
};

View File

@ -108,6 +108,10 @@
context.jamClient.ClosePreviewRecording();
}
function onCancel() {
return false;
}
function discardRecording(e) {
resetForm();
@ -323,7 +327,8 @@
function initialize() {
var dialogBindings = {
'beforeShow': beforeShow,
'afterHide': afterHide
'afterHide': afterHide,
'onCancel': onCancel
};
app.bindDialog('recordingFinished', dialogBindings);

View File

@ -205,6 +205,8 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
showInitial: () =>
@logger.debug("showing #{@state.name}")
@sampleRate = context.jamClient.GetSampleRate()
@sampleRateForFilename = if @sampleRate == 48 then '48' else '44'
@attempts = @attempts + 1
this.expectTransition()
context.JK.SubscriptionUtils.subscribe('jam_track_right', @jamTrack.jam_track_right_id).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onJamTrackRightEvent)
@ -350,17 +352,18 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
checkState: () =>
# check for the success state against the local state of the client... if it's playable, then we should be OK
@trackDetail = context.jamClient.JamTrackGetTrackDetail (@jamTrack.id)
fqId = "#{@jamTrack.id}-#{@sampleRateForFilename}"
@trackDetail = context.jamClient.JamTrackGetTrackDetail (fqId)
@logger.debug("DownloadJamTrack: JamTrackGetTrackDetail.key_state: " + @trackDetail.key_state)
@logger.debug("DownloadJamTrack: JamTrackGetTrackDetail(#{fqId}).key_state: " + @trackDetail.key_state, @trackDetail)
# first check if the version is not the same; if so, invalidate.
if @trackDetail.version?
if @jamTrack.version != @trackDetail.version
@logger.info("DownloadJamTrack: JamTrack on disk is different version (stored: #{@trackDetail.version}, server: #{@jamTrack.version}. Invalidating")
context.jamClient.InvalidateJamTrack(@jamTrack.id)
@trackDetail = context.jamClient.JamTrackGetTrackDetail (@jamTrack.id)
context.jamClient.InvalidateJamTrack("#{@jamTrack.id}-#{@sampleRateForFilename}")
@trackDetail = context.jamClient.JamTrackGetTrackDetail ("#{@jamTrack.id}-#{@sampleRateForFilename}")
if @trackDetail.version?
@logger.error("after invalidating package, the version is still wrong!")
@ -447,9 +450,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
@attemptedEnqueue = true
@ajaxEnqueueAborted = false
sampleRate = context.jamClient.GetSampleRate()
@rest.enqueueJamTrack({id: @jamTrack.id, sample_rate: sampleRate})
@rest.enqueueJamTrack({id: @jamTrack.id, sample_rate: @sampleRate})
.done(this.processEnqueueJamTrack)
.fail(this.processEnqueueJamTrackFail)

View File

@ -53,6 +53,7 @@
var playbackMode = PlaybackMode.EveryWhere;
var monitorPlaybackTimeout = null;
var playbackMonitorMode = PLAYBACK_MONITOR_MODE.MEDIA_FILE;
var monitoring = false;
function init() {
updateSliderPosition(0);
@ -210,6 +211,9 @@
}
}
function monitorRecordingPlayback() {
if(!monitoring) {
return;
}
if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
var positionMs = context.jamClient.SessionCurrrentJamTrackPlayPosMs();
var duration = context.jamClient.SessionGetJamTracksPlayDurationMs();
@ -262,7 +266,7 @@
}
// at the end of the play, the duration sets to 0, as does currentTime. but isPlaying does not reset to
//logger.debug("currentTimeMs, durationTimeMs, mode", currentTimeMs, durationTimeMs, playbackMonitorMode);
logger.debug("currentTimeMs, durationTimeMs, mode", currentTimeMs, durationTimeMs, playbackMonitorMode);
if(currentTimeMs == 0 && seenActivity) {
if(playbackPlaying) {
isPlaying = false;
@ -355,7 +359,7 @@
}
function startMonitor(_playbackMonitorMode) {
monitoring = true;
// resets everything to zero
init();
@ -373,6 +377,7 @@
}
function stopMonitor() {
monitoring = false;
logger.debug("playbackControl.stopMonitor")
if(monitorPlaybackTimeout!= null) {
clearTimeout(monitorPlaybackTimeout);

View File

@ -932,9 +932,9 @@
}
if(optionRequiresMultiplayerProfile()) {
if(context.JK.guardAgainstSinglePlayerProfile(app).canPlay == false) {
return false;
}
// if(context.JK.guardAgainstSinglePlayerProfile(app).canPlay == false) {
// return false;
//}
}
var valid = beforeMoveStep();

View File

@ -94,6 +94,7 @@
var claimedRecording = null;
var backing_track_path = null;
var jamTrack = null;
var musicianAccessOnJoin; // was this a private or public session when the user tried to joined?
var metronomeMixer = null;
var playbackControls = null;
@ -211,16 +212,7 @@
rest.getSessionHistory(data.id)
.done(function(musicSession) {
var singlePlayerCheckOK = true;
// to know whether we are allowed to be in this session, we have to check if we are the creator when checking against single player functionality
if(musicSession.user_id != context.JK.currentUserId) {
var canPlay = context.JK.guardAgainstSinglePlayerProfile(app, function () {
promptLeave = false;
});
singlePlayerCheckOK = canPlay.canPlay;
}
if(singlePlayerCheckOK) {
musicianAccessOnJoin = musicSession.musician_access;;
var shouldVerifyNetwork = musicSession.musician_access;
gearUtils.guardAgainstInvalidConfiguration(app, shouldVerifyNetwork)
@ -270,17 +262,6 @@
});
})
})
}
else {
if(canPlay.dialog) {
canPlay.dialog.one(EVENTS.DIALOG_CLOSED, function(e, data) {
if(data.canceled) {
promptLeave = false;
window.location = '/client#/home'
}
})
}
}
})
.fail(function() {
@ -308,188 +289,209 @@
function afterCurrentUserLoaded() {
var sessionModel = context.JK.CurrentSessionModel;
$(sessionModel.recordingModel)
// now check if the user can play in a session with others
var deferred = new $.Deferred();
if(musicianAccessOnJoin) {
deferred = context.JK.guardAgainstSinglePlayerProfile(app, function () {
promptLeave = false;
});
}
else {
deferred.resolve();
}
deferred.fail(function(result) {
if(!result.controlled_location) {
window.location="/client#/home"
}
})
.done(function() {logger.debug("user has passed all session guards")
promptLeave = true;
var sessionModel = context.JK.CurrentSessionModel;
$(sessionModel.recordingModel)
.on('startingRecording', function(e, data) {
displayStartingRecording();
lockControlsforJamTrackRecording();
displayStartingRecording();
lockControlsforJamTrackRecording();
})
.on('startedRecording', function(e, data) {
if(data.reason) {
var reason = data.reason;
var detail = data.detail;
var title = "Could Not Start Recording";
if(data.reason == 'client-no-response') {
notifyWithUserInfo(title, 'did not respond to the start signal.', detail);
}
else if(data.reason == 'empty-recording-id') {
app.notifyAlert(title, "No recording ID specified.");
}
else if(data.reason == 'missing-client') {
notifyWithUserInfo(title, 'could not be signalled to start recording.', detail);
}
else if(data.reason == 'already-recording') {
app.notifyAlert(title, 'Already recording. If this appears incorrect, try restarting JamKazam.');
}
else if(data.reason == 'recording-engine-unspecified') {
notifyWithUserInfo(title, 'had a problem writing recording data to disk.', detail);
}
else if(data.reason == 'recording-engine-create-directory') {
notifyWithUserInfo(title, 'had a problem creating a recording folder.', detail);
}
else if(data.reason == 'recording-engine-create-file') {
notifyWithUserInfo(title, 'had a problem creating a recording file.', detail);
}
else if(data.reason == 'recording-engine-sample-rate') {
notifyWithUserInfo(title, 'had a problem recording at the specified sample rate.', detail);
}
else if(data.reason == 'rest') {
var jqXHR = detail[0];
app.notifyServerError(jqXHR);
}
else {
notifyWithUserInfo(title, 'Error Reason: ' + reason);
}
displayDoneRecording();
}
else
{
displayStartedRecording();
displayWhoCreated(data.clientId);
lockControlsforJamTrackRecording();
}
})
.on('stoppingRecording', function(e, data) {
displayStoppingRecording(data);
unlockControlsforJamTrackRecording();
})
.on('stoppedRecording', function(e, data) {
unlockControlsforJamTrackRecording();
if(sessionModel.selfOpenedJamTracks()) {
var timeline = context.jamClient.GetJamTrackTimeline();
rest.addRecordingTimeline(data.recordingId, timeline)
.fail(function(){
app.notify(
{ title: "Unable to Add JamTrack Volume Data",
text: "The volume of the JamTrack will not be correct in the recorded mix." },
null,
true);
})
}
if(data.reason) {
logger.warn("Recording Discarded: ", data);
var reason = data.reason;
var detail = data.detail;
var title = "Recording Discarded";
if(data.reason == 'client-no-response') {
notifyWithUserInfo(title, 'did not respond to the stop signal.', detail);
}
else if(data.reason == 'missing-client') {
notifyWithUserInfo(title, 'could not be signalled to stop recording.', detail);
}
else if(data.reason == 'empty-recording-id') {
app.notifyAlert(title, "No recording ID specified.");
}
else if(data.reason == 'wrong-recording-id') {
app.notifyAlert(title, "Wrong recording ID specified.");
}
else if(data.reason == 'not-recording') {
app.notifyAlert(title, "Not currently recording.");
}
else if(data.reason == 'already-stopping') {
app.notifyAlert(title, "Already stopping the current recording.");
}
else if(data.reason == 'start-before-stop') {
notifyWithUserInfo(title, 'asked that we start a new recording; cancelling the current one.', detail);
}
else {
app.notifyAlert(title, "Error reason: " + reason);
}
displayDoneRecording();
}
else {
displayDoneRecording();
promptUserToSave(data.recordingId, timeline);
}
})
.on('abortedRecording', function(e, data) {
if(data.reason) {
var reason = data.reason;
var detail = data.detail;
var title = "Recording Cancelled";
var title = "Could Not Start Recording";
if(data.reason == 'client-no-response') {
notifyWithUserInfo(title, 'did not respond to the start signal.', detail);
notifyWithUserInfo(title, 'did not respond to the start signal.', detail);
}
else if(data.reason == 'empty-recording-id') {
app.notifyAlert(title, "No recording ID specified.");
}
else if(data.reason == 'missing-client') {
notifyWithUserInfo(title, 'could not be signalled to start recording.', detail);
notifyWithUserInfo(title, 'could not be signalled to start recording.', detail);
}
else if(data.reason == 'populate-recording-info') {
notifyWithUserInfo(title, 'could not synchronize with the server.', detail);
else if(data.reason == 'already-recording') {
app.notifyAlert(title, 'Already recording. If this appears incorrect, try restarting JamKazam.');
}
else if(data.reason == 'recording-engine-unspecified') {
notifyWithUserInfo(title, 'had a problem writing recording data to disk.', detail);
notifyWithUserInfo(title, 'had a problem writing recording data to disk.', detail);
}
else if(data.reason == 'recording-engine-create-directory') {
notifyWithUserInfo(title, 'had a problem creating a recording folder.', detail);
notifyWithUserInfo(title, 'had a problem creating a recording folder.', detail);
}
else if(data.reason == 'recording-engine-create-file') {
notifyWithUserInfo(title, 'had a problem creating a recording file.', detail);
notifyWithUserInfo(title, 'had a problem creating a recording file.', detail);
}
else if(data.reason == 'recording-engine-sample-rate') {
notifyWithUserInfo(title, 'had a problem recording at the specified sample rate.', detail);
notifyWithUserInfo(title, 'had a problem recording at the specified sample rate.', detail);
}
else if(data.reason == 'rest') {
var jqXHR = detail[0];
app.notifyServerError(jqXHR);
}
else {
app.notifyAlert(title, "Error reason: " + reason);
notifyWithUserInfo(title, 'Error Reason: ' + reason);
}
displayDoneRecording();
}
else
{
displayStartedRecording();
displayWhoCreated(data.clientId);
lockControlsforJamTrackRecording();
}
})
.on('stoppingRecording', function(e, data) {
displayStoppingRecording(data);
unlockControlsforJamTrackRecording();
})
.on('stoppedRecording', function(e, data) {
unlockControlsforJamTrackRecording();
if(sessionModel.selfOpenedJamTracks()) {
var timeline = context.jamClient.GetJamTrackTimeline();
rest.addRecordingTimeline(data.recordingId, timeline)
.fail(function(){
app.notify(
{ title: "Unable to Add JamTrack Volume Data",
text: "The volume of the JamTrack will not be correct in the recorded mix." },
null,
true);
})
}
if(data.reason) {
logger.warn("Recording Discarded: ", data);
var reason = data.reason;
var detail = data.detail;
var title = "Recording Discarded";
if(data.reason == 'client-no-response') {
notifyWithUserInfo(title, 'did not respond to the stop signal.', detail);
}
else if(data.reason == 'missing-client') {
notifyWithUserInfo(title, 'could not be signalled to stop recording.', detail);
}
else if(data.reason == 'empty-recording-id') {
app.notifyAlert(title, "No recording ID specified.");
}
else if(data.reason == 'wrong-recording-id') {
app.notifyAlert(title, "Wrong recording ID specified.");
}
else if(data.reason == 'not-recording') {
app.notifyAlert(title, "Not currently recording.");
}
else if(data.reason == 'already-stopping') {
app.notifyAlert(title, "Already stopping the current recording.");
}
else if(data.reason == 'start-before-stop') {
notifyWithUserInfo(title, 'asked that we start a new recording; cancelling the current one.', detail);
}
else {
app.notifyAlert(title, "Error reason: " + reason);
}
displayDoneRecording();
}
else {
displayDoneRecording();
promptUserToSave(data.recordingId, timeline);
}
})
.on('abortedRecording', function(e, data) {
var reason = data.reason;
var detail = data.detail;
var title = "Recording Cancelled";
if(data.reason == 'client-no-response') {
notifyWithUserInfo(title, 'did not respond to the start signal.', detail);
}
else if(data.reason == 'missing-client') {
notifyWithUserInfo(title, 'could not be signalled to start recording.', detail);
}
else if(data.reason == 'populate-recording-info') {
notifyWithUserInfo(title, 'could not synchronize with the server.', detail);
}
else if(data.reason == 'recording-engine-unspecified') {
notifyWithUserInfo(title, 'had a problem writing recording data to disk.', detail);
}
else if(data.reason == 'recording-engine-create-directory') {
notifyWithUserInfo(title, 'had a problem creating a recording folder.', detail);
}
else if(data.reason == 'recording-engine-create-file') {
notifyWithUserInfo(title, 'had a problem creating a recording file.', detail);
}
else if(data.reason == 'recording-engine-sample-rate') {
notifyWithUserInfo(title, 'had a problem recording at the specified sample rate.', detail);
}
else {
app.notifyAlert(title, "Error reason: " + reason);
}
displayDoneRecording();
})
sessionModel.subscribe('sessionScreen', sessionChanged);
sessionModel.joinSession(sessionId)
sessionModel.subscribe('sessionScreen', sessionChanged);
sessionModel.joinSession(sessionId)
.fail(function(xhr, textStatus, errorMessage) {
if(xhr.status == 404) {
// we tried to join the session, but it's already gone. kick user back to join session screen
promptLeave = false;
context.window.location = "/client#/findSession";
app.notify(
{ title: "Unable to Join Session",
text: "The session you attempted to join is over."
},
null,
true);
if(xhr.status == 404) {
// we tried to join the session, but it's already gone. kick user back to join session screen
promptLeave = false;
context.window.location = "/client#/findSession";
app.notify(
{ title: "Unable to Join Session",
text: "The session you attempted to join is over."
},
null,
true);
}
else if(xhr.status == 422) {
var response = JSON.parse(xhr.responseText);
if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") {
app.notifyAlert("No Inputs Configured", $('<span>You will need to reconfigure your audio device.</span>'));
}
else if(xhr.status == 422) {
var response = JSON.parse(xhr.responseText);
if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") {
app.notifyAlert("No Inputs Configured", $('<span>You will need to reconfigure your audio device.</span>'));
}
else if(response["errors"] && response["errors"]["music_session"] && response["errors"]["music_session"][0] == ["is currently recording"]) {
promptLeave = false;
context.window.location = "/client#/findSession";
app.notify( { title: "Unable to Join Session", text: "The session is currently recording." }, null, true);
}
else {
app.notifyServerError(xhr, 'Unable to Join Session');
}
else if(response["errors"] && response["errors"]["music_session"] && response["errors"]["music_session"][0] == ["is currently recording"]) {
promptLeave = false;
context.window.location = "/client#/findSession";
app.notify( { title: "Unable to Join Session", text: "The session is currently recording." }, null, true);
}
else {
app.notifyServerError(xhr, 'Unable to Join Session');
app.notifyServerError(xhr, 'Unable to Join Session');
}
}
else {
app.notifyServerError(xhr, 'Unable to Join Session');
}
});
})
}
// not leave session but leave screen
@ -2727,17 +2729,22 @@
// XXX: test with this removed; it should be unnecessary
context.jamClient.JamTrackStopPlay();
var sampleRate = context.jamClient.GetSampleRate()
var sampleRateForFilename = sampleRate == 48 ? '48' : '44'
var fqId = jamTrack.id + '-' + sampleRateForFilename
if(jamTrack.jmep)
{
logger.debug("setting jmep data")
context.jamClient.JamTrackLoadJmep(jamTrack.id, jamTrack.jmep)
context.jamClient.JamTrackLoadJmep(fqId, jamTrack.jmep)
}
else {
logger.debug("no jmep data for jamtrack")
}
// JamTrackPlay means 'load'
var result = context.jamClient.JamTrackPlay(jamTrack.id);
var result = context.jamClient.JamTrackPlay(fqId);
if(!result) {
app.notify(

View File

@ -136,20 +136,19 @@
return false;
}
if(context.JK.guardAgainstSinglePlayerProfile(app).canPlay) {
gearUtils.guardAgainstInvalidConfiguration(app)
.fail(function() {
app.notify(
{ title: "Unable to Join Session",
text: "You can only join a session once you have working audio gear and a tested internet connection."
});
})
.done(function() {
if (successCallback) {
successCallback();
}
});
}
gearUtils.guardAgainstInvalidConfiguration(app)
.fail(function() {
app.notify(
{ title: "Unable to Join Session",
text: "You can only join a session once you have working audio gear and a tested internet connection."
});
})
.done(function() {
if (successCallback) {
successCallback();
}
});
}
sessionUtils.joinSession = function(sessionId) {

View File

@ -11,7 +11,7 @@
var $content = null;
function beforeShow(data) {
clearContent();
}
function afterShow(data) {

View File

@ -581,6 +581,7 @@
logger.debug("offBackendEvent: " + alertData.name + '.' + namespace, alertData)
$(document).off(alertData.name + '.' + namespace);
}
/*
* Loads a listbox or dropdown with the values in input_array, setting the option value
* to the id_field and the option text to text_field. It will preselect the option with
@ -1125,70 +1126,6 @@
return true;
}
context.JK.guardAgainstSinglePlayerProfile = function(app, beforeCallback) {
var canPlayWithOthers = context.JK.GearUtilsInstance.canPlayWithOthers();
if(!canPlayWithOthers.canPlay) {
logger.debug("guarding against single player profile")
var $dialog = app.layout.showDialog('single-player-profile-dialog');
// so that callers can check dialog result
canPlayWithOthers.dialog = $dialog;
// allow callers to take action before default behavior
if(beforeCallback) {
$dialog.one(EVENTS.DIALOG_CLOSED, beforeCallback);
}
$dialog.one(EVENTS.DIALOG_CLOSED, function(e, data) {
if(!data.canceled) {
if(data.result.choice == 'private_session') {
var data = {
createType: 'quick-start',
timezone: {},
recurring_mode: {},
language: {},
band: {},
musician_access: {},
fans_access: {},
rsvp_slots: [],
open_rsvps: false
};
context.JK.privateSessionSettings(data)
context.JK.createSession(app, data)
.done(function(response) {
var sessionId = response.id;
context.JK.GA.trackSessionCount(true, true, 0);
// we redirect to the session screen, which handles the REST call to POST /participants.
logger.debug("joining session screen: " + sessionId)
context.location = '/client#/session/' + sessionId;
})
.fail(function(jqXHR) {
logger.debug("unable to schedule a private session")
app.notifyServerError(jqXHR, "Unable to schedule a private session");
})
}
else if(data.result.choice == 'gear_setup') {
window.location = '/client#/account/audio'
}
else
{
logger.error("unknown choice: " + data.result.choice)
alert("unknown choice: " + data.result.choice)
}
}
})
}
return canPlayWithOthers;
}
context.JK.createSession = function(app, data) {

View File

@ -10,6 +10,7 @@
var rest = new context.JK.Rest();
context.JK.GearUtils = gearUtils;
var logger = context.JK.logger;
var ALERT_NAMES = context.JK.ALERT_NAMES;
var ASSIGNMENT = context.JK.ASSIGNMENT;
var VOICE_CHAT = context.JK.VOICE_CHAT;
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
@ -30,17 +31,39 @@
return channel.assignment == ASSIGNMENT.CHAT || channel.assignment == ASSIGNMENT.OUTPUT || channel.assignment > 0;
}
gearUtils.resyncAudio = function() {
function backendMixerChange (e, data) {
if (data.text == 'deferred') {
context.JK.offBackendEvent(ALERT_NAMES.BACKEND_MIXER_CHANGE, 'gearUtilsResyncAudio', backendMixerChange)
console.log("context.jamClient.FTUEGetExpectedLatency()", context.jamClient.FTUEGetExpectedLatency().latency)
deferred.resolve();
}
;
}
var deferred = new $.Deferred();
context.JK.onBackendEvent(ALERT_NAMES.BACKEND_MIXER_CHANGE, 'gearUtilsResyncAudio', backendMixerChange);
context.jamClient.SessionAudioResync();
// give backend 5 seconds to timeout
deferred.timer = setTimeout(function() {
deferred.rejectWith('timeout');
context.JK.offBackendEvent(ALERT_NAMES.BACKEND_MIXER_CHANGE, 'gearUtilsResyncAudio', backendMixerChange)
}, 5000);
return deferred;
}
// to play with others, you have to have inputs,
// as well have a score below 20 ms
gearUtils.canPlayWithOthers = function(profile) {
if(gon.global.gear_check_reload_audio) {
if (!context.jamClient.IsAudioStarted()) {
context.jamClient.ReloadAudioSystem(true, true, true);
context.jamClient.StopAudio();
}
}
var isNoInputProfile = gearUtils.isNoInputProfile(profile);
var expectedLatency = context.jamClient.FTUEGetExpectedLatency();
@ -431,6 +454,84 @@
return deferred;
}
context.JK.guardAgainstSinglePlayerProfile = function(app, beforeCallback) {
var deferred = new $.Deferred();
var canPlayWithOthers = context.JK.GearUtilsInstance.canPlayWithOthers();
if(!canPlayWithOthers.canPlay) {
logger.debug("guarding against single player profile")
var $dialog = app.layout.showDialog('single-player-profile-dialog');
// so that callers can check dialog result
canPlayWithOthers.dialog = $dialog;
// allow callers to take action before default behavior
if(beforeCallback) {
$dialog.one(EVENTS.DIALOG_CLOSED, beforeCallback);
}
$dialog.one(EVENTS.DIALOG_CLOSED, function(e, data) {
if(data.canceled) {
deferred.rejectWith(canPlayWithOthers, [{ reason: 'canceled', controlled_location:false }])
}
else {
if(data.result.choice == 'private_session') {
var data = {
createType: 'quick-start',
timezone: {},
recurring_mode: {},
language: {},
band: {},
musician_access: {},
fans_access: {},
rsvp_slots: [],
open_rsvps: false
};
context.JK.privateSessionSettings(data)
context.JK.createSession(app, data)
.done(function(response) {
var sessionId = response.id;
context.JK.GA.trackSessionCount(true, true, 0);
deferred.rejectWith(canPlayWithOthers, [{ reason: 'private_session', controlled_location:true }])
// we redirect to the session screen, which handles the REST call to POST /participants.
logger.debug("joining session screen: " + sessionId)
context.location = '/client#/session/' + sessionId;
})
.fail(function(jqXHR) {
deferred.rejectWith(canPlayWithOthers, [{ reason: 'gear_setup', controlled_location:false }])
logger.debug("unable to schedule a private session")
app.notifyServerError(jqXHR, "Unable to schedule a private session");
})
}
else if(data.result.choice == 'gear_setup') {
deferred.rejectWith(canPlayWithOthers, [{ reason: data.result.choice,controlled_location:true }])
window.location = '/client#/account/audio'
}
else
{
deferred.rejectWith(canPlayWithOthers, [{ reason: 'unknown', controlled_location:false }])
logger.error("unknown choice: " + data.result.choice)
alert("unknown choice: " + data.result.choice)
}
}
})
}
else {
deferred.resolveWith(canPlayWithOthers)
}
return deferred;
}
gearUtils.guardAgainstActiveProfileMissing = function (app, backendInfo) {

View File

@ -1,3 +1,4 @@
// see audioWidgets.css
.recording-controls {

View File

@ -7,6 +7,10 @@ class ApiJamTracksController < ApiController
respond_to :json
def log
@log || Logging.logger[ApiJamTracksController]
end
def show
@jam_track = JamTrack.find_by_plan_code!(params[:plan_code])
end
@ -70,7 +74,7 @@ class ApiJamTracksController < ApiController
def download
if @jam_track_right.valid?
sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i
if (@jam_track_right && @jam_track_right.ready?(sample_rate))
if @jam_track_right && @jam_track_right.ready?(sample_rate)
@jam_track_right.update_download_count
@jam_track_right.last_downloaded_at = Time.now
@jam_track_right.save!
@ -86,7 +90,8 @@ class ApiJamTracksController < ApiController
def enqueue
sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i
@jam_track_right.enqueue_if_needed(sample_rate)
enqueued = @jam_track_right.enqueue_if_needed(sample_rate)
log.debug("jamtrack #{enqueued ? "ENQUEUED" : "NOT ENQUEUED"}: jam_track_right=#{@jam_track_right.id} sample_rate=#{sample_rate} ")
render :json => { :message => "enqueued" }, :status => 200
end
@ -102,14 +107,31 @@ class ApiJamTracksController < ApiController
return
end
jamtrack_ids = jamtrack_holder[:tracks]
jamtracks = jamtrack_holder[:tracks]
unless jamtrack_ids.kind_of?(Array)
unless jamtracks.kind_of?(Array)
render :json => {message: 'jamtracks:tracks parameter must be an array'}, :status => 422
return
end
# jamtracks come in the form id-44 or id-48, so we need to do a little extra parsing
puts "#{jamtracks.inspect}"
jamtrack_ids = Set.new
jamtracks_fq_ids = Set.new
jamtracks.each do |jamtrack|
rindex = jamtrack.rindex('-')
if rindex
id = jamtrack[0..(rindex-1)]
jamtrack_ids << id
jamtracks_fq_ids << jamtrack # includes sample rate
end
end
puts "#{jamtrack_ids.inspect} #{jamtracks_fq_ids.inspect}"
@jam_tracks = JamTrackRight.list_keys(current_user, jamtrack_ids)
@jamtracks_fq_ids = jamtracks_fq_ids
end
private

View File

@ -1,9 +1,23 @@
object @jam_tracks
node do |jam_track|
{
id: jam_track['id'].to_s,
private: jam_track['private_key'],
error: jam_track['private_key'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' )
}
id = jam_track['id']
result = { id: id }
if @jamtracks_fq_ids.include?("#{id}-44")
result['44'] = {
private: jam_track['private_key_44'],
error: jam_track['private_key_44'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' )
}
end
if @jamtracks_fq_ids.include?("#{id}-48")
result['48'] = {
private: jam_track['private_key_48'],
error: jam_track['private_key_48'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' )
}
end
result
end

View File

@ -332,6 +332,5 @@ if defined?(Bundler)
config.alerts_api_enabled = true
config.gear_check_ignore_high_latency = false
config.gear_check_reload_audio = true
end
end

View File

@ -14,5 +14,4 @@ Gon.global.recurly_public_api_key = Rails.application.config.recurly_public_api_
Gon.global.one_free_jamtrack_per_user = Rails.application.config.one_free_jamtrack_per_user
Gon.global.video_available = Rails.application.config.video_available
Gon.global.gear_check_ignore_high_latency = Rails.application.config.gear_check_ignore_high_latency
Gon.global.gear_check_reload_audio = Rails.application.config.gear_check_reload_audio
Gon.global.env = Rails.env

View File

@ -143,30 +143,33 @@ describe ApiJamTracksController do
end
it "download depends on rights" do
get :download, :id=>@jam_track.id
get :download, :id=>@jam_track.id, sample_rate: 48
response.status.should == 403
right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
get :download, :id=>@jam_track.id
get :download, :id=>@jam_track.id, sample_rate: 48
response.status.should == 202
right.download_count.should eq(0)
right.private_key.should be_nil
right.private_key_44.should be_nil
right.private_key_48.should be_nil
qname = "#{ResqueSpec.queue_name(JamRuby::JamTracksBuilder)}"
#puts "ResqueSpec.peek(qname)#{ResqueSpec.peek(qname)}"
JamTracksBuilder.should have_queued(right.id,nil).in(:jam_tracks_builder)
JamTracksBuilder.should have_queued(right.id,48).in(:jam_tracks_builder)
expect(ResqueSpec.peek(qname).present?).to eq(true)
ResqueSpec.perform_next(qname)
JamTracksBuilder.should_not have_queued(right.id,nil).in(:jam_tracks_builder)
right.reload
right.private_key.should_not be_nil
right.private_key_44.should be_nil
right.private_key_48.should_not be_nil
right.download_count.should eq(0)
get :download, :id=>@jam_track.id
get :download, :id=>@jam_track.id, sample_rate: 48
response.status.should == 302
response.location.should =~ /.*#{Regexp.escape(right.filename)}.*/
puts response.location
response.location.should =~ /.*#{Regexp.escape(right.filename(:url_48))}.*/
right.reload
right.download_count.should eq(1)
@ -182,7 +185,8 @@ describe ApiJamTracksController do
get :download, :id=>@jam_track.id, :sample_rate=>44
response.status.should == 202
right.download_count.should eq(0)
right.private_key.should be_nil
right.private_key_44.should be_nil
right.private_key_48.should be_nil
qname = "#{ResqueSpec.queue_name(JamRuby::JamTracksBuilder)}"
#puts "ResqueSpec.peek(qname)#{ResqueSpec.peek(qname)}"
@ -193,12 +197,13 @@ describe ApiJamTracksController do
JamTracksBuilder.should_not have_queued(right.id, 44).in(:jam_tracks_builder)
right.reload
right.private_key.should_not be_nil
right.private_key_44.should_not be_nil
right.private_key_48.should be_nil
right.download_count.should eq(0)
get :download, :id=>@jam_track.id, :sample_rate=>44
response.status.should == 302
response.location.should =~ /.*#{Regexp.escape(right.filename)}.*/
response.location.should =~ /.*#{Regexp.escape(right.filename(:url_44))}.*/
right.reload
right.download_count.should eq(1)
@ -216,53 +221,66 @@ describe ApiJamTracksController do
end
it "track with no rights" do
get :keys, jamtracks: { tracks: [@jam_track.id] }
get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44"] }
response.status.should == 200
json = JSON.parse(response.body)
json.length.should == 1
json[0]['id'].should == @jam_track.id.to_s
json[0]['private'].should be_nil
json[0]['error'].should == 'not_purchased'
json[0]['44'].should_not be_nil
json[0]['44']['private'].should be_nil
json[0]['44']['error'].should == 'not_purchased'
json[0]['48'].should be_nil
end
it "track with no key" do
right = FactoryGirl.create(:jam_track_right, user: @user, private_key: nil, jam_track: @jam_track)
right = FactoryGirl.create(:jam_track_right, user: @user, private_key_44: nil, private_key_48:nil, jam_track: @jam_track)
get :keys, jamtracks: { tracks: [@jam_track.id] }
get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] }
response.status.should == 200
json = JSON.parse(response.body)
json.length.should == 1
json[0]['id'].should == @jam_track.id.to_s
json[0]['private'].should be_nil
json[0]['error'].should == 'no_key'
json[0]['44'].should_not be_nil
json[0]['44']['private'].should be_nil
json[0]['44']['error'].should == 'no_key'
json[0]['48'].should_not be_nil
json[0]['48']['private'].should be_nil
json[0]['48']['error'].should == 'no_key'
end
it "track with key" do
right = FactoryGirl.create(:jam_track_right, user: @user, private_key: 'abc', jam_track: @jam_track)
get :keys, jamtracks: { tracks: [@jam_track.id] }
right = FactoryGirl.create(:jam_track_right, user: @user, private_key_44: 'abc', private_key_48:nil, jam_track: @jam_track)
get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] }
response.status.should == 200
json = JSON.parse(response.body)
json.length.should == 1
json[0]['id'].should == @jam_track.id.to_s
json[0]['private'].should eq('abc')
json[0]['error'].should be_nil
json[0]['44'].should_not be_nil
json[0]['44']['private'].should eq('abc')
json[0]['44']['error'].should be_nil
json[0]['48'].should_not be_nil
json[0]['48']['private'].should be_nil
json[0]['48']['error'].should == 'no_key'
end
it "non-owning user asking for a real track" do
right = FactoryGirl.create(:jam_track_right, user: FactoryGirl.create(:user), private_key: 'abc', jam_track: @jam_track)
get :keys, jamtracks: { tracks: [@jam_track.id] }
right = FactoryGirl.create(:jam_track_right, user: FactoryGirl.create(:user), private_key_44: 'abc', private_key_48:nil, jam_track: @jam_track)
get :keys, jamtracks: { tracks: ["#{@jam_track.id}-44", "#{@jam_track.id}-48"] }
response.status.should == 200
json = JSON.parse(response.body)
json[0]['id'].should == @jam_track.id.to_s
json[0]['private'].should be_nil
json[0]['error'].should == 'not_purchased'
json[0]['44'].should_not be_nil
json[0]['44']['private'].should be_nil
json[0]['44']['error'].should eq('not_purchased')
json[0]['48'].should_not be_nil
json[0]['48']['private'].should be_nil
json[0]['48']['error'].should eq('not_purchased')
end
end
describe "enqueue" do
it "success" do
right = FactoryGirl.create(:jam_track_right, user: @user, signed: false)
right = FactoryGirl.create(:jam_track_right, user: @user, signed_44: false, signed_48:false)
right.signing_queued_at.should be_nil
post :enqueue, {:format=>'json', :id=>right.jam_track.id}
response.should be_success

View File

@ -135,11 +135,15 @@ describe "JamTrack Shopping", :js => true, :type => :feature, :capybara_feature
find_jamtrack jt_us
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_us.id}\"]").trigger(:click)
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_ww.id}\"]").trigger(:click)
find('.shopping-sub-total', text: "Subtotal:$ #{jt_us.price}")
find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
find('.shopping-sub-total', text: "Subtotal: $ #{jt_us.price + jt_ww.price}")
find_jamtrack jt_ww
find("a.jamtrack-add-cart[data-jamtrack-id=\"#{jt_ww.id}\"]").trigger(:click)
find('.shopping-sub-total', text: "Subtotal:$ #{jt_us.price + jt_ww.price}")
#find('a.button-orange', text: 'CONTINUE SHOPPING').trigger(:click)
end
it "can expand" do