merge from develop

This commit is contained in:
Seth Call 2016-07-09 06:21:48 -05:00
commit b7d47eca4f
15 changed files with 234 additions and 69 deletions

View File

@ -360,4 +360,6 @@ packaged_test_drive.sql
packaged_test_drive2.sql
jamclass_report.sql
jamblasters_network.sql
rails4_migration.sql
immediate_recordings.sql
nullable_user_id_jamblaster.sql
rails4_migration.sql

View File

@ -0,0 +1 @@
ALTER TABLE recordings ADD COLUMN immediate BOOLEAN DEFAULT FALSE;

View File

@ -0,0 +1 @@
ALTER TABLE jamblasters ALTER user_id DROP NOT NULL;

View File

@ -9,7 +9,6 @@ module JamRuby
has_many :users, class_name: 'JamRuby::User', through: :jamblasters_users
has_many :jamblaster_pairing_requests, class_name: "JamRuby::JamblasterPairingRequest", foreign_key: :jamblaster_id
belongs_to :connection, class_name: "JamRuby::Connection", foreign_key: "client_id"
validates :user, presence: true
validates :serial_no, uniqueness: true
validates :client_id, uniqueness: true
@ -25,6 +24,18 @@ module JamRuby
jamblaster_pairing_requests.where(active: true).first
end
def self.bootstrap(serialno)
jb = Jamblaster.find_by_serial_no(serialno)
if jb
return jb
end
jb = Jamblaster.new
jb.serial_no = serialno
jb.save
jb
end
class << self
@@mq_router = MQRouter.new

View File

@ -135,7 +135,7 @@ module JamRuby
mix.recording = recording
mix.user = user
mix.save
mix[:ogg_url] = construct_filename(mix.created_at, recording.id, mix.id, type='ogg')
mix[:ogg_url] = construct_filename(mix.created_at, recording.id, mix.id, mix.default_type)
mix[:mp3_url] = construct_filename(mix.created_at, recording.id, mix.id, type='mp3')
mix.save
mix.is_skip_mount_uploader = false
@ -205,8 +205,10 @@ module JamRuby
end
end
def s3_url(type='ogg')
if type == 'ogg'
def s3_url(type=default_type)
if type == 'aac'
s3_manager.s3_url(self[:ogg_url])
elsif type == 'ogg'
s3_manager.s3_url(self[:ogg_url])
else
s3_manager.s3_url(self[:mp3_url])
@ -222,10 +224,12 @@ module JamRuby
self[url_field].start_with?('http') ? self[url_field] : s3_manager.sign_url(self[url_field], {:expires => expiration_time, :response_content_type => mime_type, :secure => true})
end
def sign_url(expiration_time = 120, type='ogg')
def sign_url(expiration_time = 120, type=default_type)
type ||= 'ogg'
# expire link in 1 minute--the expectation is that a client is immediately following this link
if type == 'ogg'
if type == 'aac'
resolve_url(:ogg_url, 'audio/aac', expiration_time)
elsif type == 'ogg'
resolve_url(:ogg_url, 'audio/ogg', expiration_time)
else
resolve_url(:mp3_url, 'audio/mpeg', expiration_time)
@ -233,9 +237,11 @@ module JamRuby
end
# this is not 'secure' because, in testing, the PUT failed often in Ruby. should investigate more.
def sign_put(expiration_time = 3600 * 24, type='ogg')
def sign_put(expiration_time = 3600 * 24, type=default_type)
type ||= 'ogg'
if type == 'ogg'
if type == 'aac'
s3_manager.sign_url(self[:ogg_url], {:expires => expiration_time, :content_type => 'audio/aac', :secure => false}, :put)
elsif type == 'ogg'
s3_manager.sign_url(self[:ogg_url], {:expires => expiration_time, :content_type => 'audio/ogg', :secure => false}, :put)
else
s3_manager.sign_url(self[:mp3_url], {:expires => expiration_time, :content_type => 'audio/mpeg', :secure => false}, :put)
@ -258,19 +264,25 @@ module JamRuby
end
end
def filename(type='ogg')
def default_type
recording.immediate ? 'aac' : 'ogg'
end
def filename(type=default_type)
# construct a path for s3
QuickMix.construct_filename(self.created_at, self.recording_id, self.id, type)
end
def delete_s3_files
s3_manager.delete(filename(type='ogg')) if self[:ogg_url] && s3_manager.exists?(filename(type='ogg'))
s3_manager.delete(filename(type='mp3')) if self[:mp3_url] && s3_manager.exists?(filename(type='mp3'))
s3_manager.delete(filename(type=default_type)) if self[:ogg_url] && s3_manager.exists?(filename(type=default_type))
s3_manager.delete(filename(type='mp3')) if self[:mp3_url] && s3_manager.exists?(filename(type=default_type))
end
def self.construct_filename(created_at, recording_id, id, type='ogg')
raise "unknown ID" unless id
"recordings/#{created_at.strftime('%m-%d-%Y')}/#{recording_id}/stream-mix-#{id}.#{type}"
end
end
end

View File

@ -147,6 +147,24 @@ module JamRuby
recorded_track
end
def self.create_for_immediate(user, recording)
recorded_track = self.new
recorded_track.recording = recording
recorded_track.client_id = 'ios'
recorded_track.track_id = 'ios'
recorded_track.client_track_id = 'ios'
recorded_track.user = user
recorded_track.instrument = Instrument.find('other')
recorded_track.sound = 'stereo'
recorded_track.next_part_to_upload = 0
recorded_track.file_offset = 0
recorded_track.is_skip_mount_uploader = true
recorded_track.save
recorded_track.url = construct_filename(recording.created_at, recording.id, 'ios', 'aac')
recorded_track.save
recorded_track.is_skip_mount_uploader = false
recorded_track
end
def sign_url(expiration_time = 120)
s3_manager.sign_url(self[:url], {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => true})
end
@ -226,9 +244,9 @@ module JamRuby
private
def self.construct_filename(created_at, recording_id, client_track_id)
def self.construct_filename(created_at, recording_id, client_track_id, type='ogg')
raise "unknown ID" unless client_track_id
"recordings/#{created_at.strftime('%m-%d-%Y')}/#{recording_id}/track-#{client_track_id}.ogg"
"recordings/#{created_at.strftime('%m-%d-%Y')}/#{recording_id}/track-#{client_track_id}.#{type}"
end
end
end

View File

@ -132,6 +132,7 @@ module JamRuby
end
end
# this should be used to cleanup a recording that we detect is no longer running
def abort
recording.music_session.claimed_recording_id = nil
@ -212,6 +213,44 @@ module JamRuby
ChatMessage.joins(:claimed_recording => [:recording]).where('recordings.id = ?', self.id).where('chat_messages.target_user_id = ?', user.id).count > 0
end
# creates a recording, and then claims it in one shot.
def self.create_immediately(owner, params)
recording = Recording.new
recording.music_session = nil
recording.owner = owner
recording.band = nil
recording.immediate = true # immediate in practice means 'the ios app uploaded this'
recording.video = params[:record_video]
if recording.save
QuickMix.create(recording, owner)
recording.recorded_tracks << RecordedTrack.create_for_immediate(owner, recording)
recording.save
end
if recording.errors.any?
return recording
end
recording.stop
if recording.errors.any?
return recording
end
recording.reload
claim = recording.claim(owner, params[:name], params[:description], Genre.find_by_id(params[:genre]), params[:is_public], upload_to_youtube = params[:upload_to_youtube])
if claim.errors.any?
return claim
end
recording
end
# Start recording a session.
def self.start(music_session, owner, record_video: false)
recording = nil
@ -277,7 +316,7 @@ module JamRuby
# Called when a user wants to "claim" a recording. To do this, the user must have been one of the tracks in the recording.
def claim(user, name, description, genre, is_public, upload_to_youtube=false)
upload_to_youtube = !!upload_to_youtube # Correct where nil is borking save
unless self.users.exists?(user.id)
if !self.users.exists?(user.id)
raise JamPermissionError, "user was not in this session"
end

View File

@ -129,7 +129,7 @@ module JamRuby
def fetch_audio_files
@input_ogg_filename = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/quick_mixer_#{@quick_mix.id}}", '.ogg'], nil)
@input_ogg_filename = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/quick_mixer_#{@quick_mix.id}}", '.' + @quick_mix.default_type], nil)
@output_mp3_filename = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/quick_mixer_#{@quick_mix.id}}", '.mp3'], nil)
@s3_manager.download(@quick_mix[:ogg_url], @input_ogg_filename)
end

View File

@ -14,6 +14,31 @@ describe Jamblaster do
user.jamblasters.should eq([])
end
describe "bootstrap" do
it "creates new" do
jb = Jamblaster.bootstrap('abcd')
jb.should_not be_nil
jb.errors.any?.should be_false
found = Jamblaster.find_by_serial_no('abcd')
found.should_not be_nil
jb.id.should eql found.id
end
it "reuses existing" do
jb = Jamblaster.bootstrap('abcd')
jb.should_not be_nil
found = Jamblaster.bootstrap('abcd')
found.should_not be_nil
jb.id.should eql found.id
end
end
describe "most_recent_pairings" do
it "basic funnction" do

View File

@ -8,13 +8,28 @@ describe Recording do
let(:s3_manager) { S3Manager.new(app_config.aws_bucket, app_config.aws_access_key_id, app_config.aws_secret_access_key) }
before do
@user = FactoryGirl.create(:user)
@user = FactoryGirl.create(:user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
@connection = FactoryGirl.create(:connection, :user => @user, :music_session => @music_session)
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
end
describe "create_immediately" do
it "success with no video" do
recording = Recording.create_immediately(@user, {name: 'My recording', description: nil, genre: Genre.first, record_video: false, is_public: true, upload_to_youtube: false})
puts "recording errros #{recording.errors.inspect}"
recording.errors.any?.should be_false
recording.reload
recording.claimed_recordings.count.should eql 1
claim = recording.claimed_recordings.first
claim.name.should eql 'My recording'
claim.description.should be_nil
claim.discarded.should be_false
claim.user.should eql @user
recording.owner.should eql @user
end
end
describe "popular_recordings" do
it "empty" do
Recording.popular_recordings.length.should eq(0)
@ -43,13 +58,13 @@ describe Recording do
sample_audio='sample.file'
in_directory_with_file(sample_audio)
let(:user2) {FactoryGirl.create(:user)}
let(:user2) { FactoryGirl.create(:user) }
let(:quick_mix) { FactoryGirl.create(:quick_mix) }
let(:quick_mix2) {
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2)
recording.claimed_recordings << FactoryGirl.create(:claimed_recording, user: user2, recording: recording)
recording.save!
FactoryGirl.create(:quick_mix, autowire: false, recording:recording, user: user2) }
FactoryGirl.create(:quick_mix, autowire: false, recording: recording, user: user2) }
let(:recording) { quick_mix.recording }
before(:each) do
@ -248,20 +263,20 @@ describe Recording do
user2_recorded_tracks.length.should == 1
user2_recorded_tracks[0].should == user2.recorded_backing_tracks[0]
end
it "should set up the recording properly when recording is started with 1 user in the session" do
@music_session.is_recording?.should be_false
@recording = Recording.start(@music_session, @user)
@music_session.reload
@music_session.recordings[0].should == @recording
@recording.owner_id.should == @user.id
@recorded_tracks = RecordedTrack.where(:recording_id => @recording.id)
@recorded_tracks.length.should == 1
@recorded_tracks.first.instrument_id == @track.instrument_id
@recorded_tracks.first.user_id == @track.connection.user_id
end
@recorded_tracks.first.user_id == @track.connection.user_id
end
it "should not start a recording if the session is already being recorded" do
Recording.start(@music_session, @user).errors.any?.should be_false
recording = Recording.start(@music_session, @user)
@ -299,7 +314,7 @@ describe Recording do
@connection2 = FactoryGirl.create(:connection, :user => @user2)
@instrument2 = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track2 = FactoryGirl.create(:track, :connection => @connection2, :instrument => @instrument2)
# @music_session.connections << @connection2
@connection2.join_the_session(@music_session, true, nil, @user2, 10)
@ -310,7 +325,7 @@ describe Recording do
@user2.recordings.length.should == 0
#@user2.recordings.first.should == @recording
end
it "should report correctly whether its tracks have been uploaded" do
@recording = Recording.start(@music_session, @user)
@recording.uploaded?.should == false
@ -320,7 +335,7 @@ describe Recording do
@recording.recorded_tracks.first.fully_uploaded = true
@recording.uploaded?.should == true
end
it "should destroy a recording and all its recorded tracks properly" do
@recording = Recording.start(@music_session, @user)
@recording.stop
@ -331,7 +346,7 @@ describe Recording do
expect { RecordedTracks.find(@recorded_track.id) }.to raise_error
end
it "should allow a user to claim a recording" do
it "should allow a user to claim a recording" do
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
@ -370,7 +385,7 @@ describe Recording do
@claimed_recording.reload
@claimed_recording.name.should == "name2"
@claimed_recording.description.should == "description2"
@claimed_recording.genre.should == @genre2
@claimed_recording.genre.should == @genre2
@claimed_recording.is_public.should == false
@claimed_recording.upload_to_youtube.should == false
end
@ -419,15 +434,15 @@ describe Recording do
@recording.all_discarded.should == false
end
it "should set youtube flag" do
it "should set youtube flag" do
@connection.join_the_session(@music_session, true, nil, @user, 10)
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
@genre = FactoryGirl.create(:genre)
@recording.claim(@user, "name", "description", @genre, true, true)
@recording.reload
@recording.users.length.should == 1
@recording.users.first.should == @user
@ -570,7 +585,7 @@ describe Recording do
@music_session.reload
@music_session.recordings[0].should == @recording
@recording.owner_id.should == @user.id
@recorded_videos = RecordedVideo.where(:recording_id => @recording.id)
@recorded_videos.should have(1).items
@recorded_videos[0].client_video_source_id.should eq(@video_source.client_video_source_id)
@ -628,11 +643,11 @@ describe Recording do
end
it "should only retrieve tracks and videos from user" do
user2 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session
music_session2 = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => @music_session, :ip_address => "2.2.2.2", :client_id => "2")
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => @music_session, :ip_address => "2.2.2.2", :client_id => "2")
connection2 = FactoryGirl.create(:connection, :user => user2, :music_session => @music_session)
track2 = FactoryGirl.create(:track, :connection => connection2, :instrument => @instrument)
track2 = FactoryGirl.create(:track, :connection => connection2, :instrument => @instrument)
video_source = FactoryGirl.create(:video_source, :connection => @connection)
video_source2 = FactoryGirl.create(:video_source, :connection => connection2)
@ -707,8 +722,8 @@ describe Recording do
end
describe "discarded_and_stale" do
let(:recording1) {FactoryGirl.create(:recording_with_track)}
let(:track1) {recording1.recorded_tracks[0]}
let(:recording1) { FactoryGirl.create(:recording_with_track) }
let(:track1) { recording1.recorded_tracks[0] }
it "no results if no recordings" do
Recording.discarded_and_stale.length.should == 0
@ -913,8 +928,8 @@ describe Recording do
end
describe "two recordings" do
let(:recording2) {FactoryGirl.create(:recording_with_track)}
let(:track2) {recording2.recorded_tracks[0]}
let(:recording2) { FactoryGirl.create(:recording_with_track) }
let(:track2) { recording2.recorded_tracks[0] }
describe "both discard" do
@ -1050,17 +1065,17 @@ describe Recording do
end
describe "delete" do
let(:mix) {FactoryGirl.create(:mix)}
let(:recording) {mix.recording}
let(:mix) { FactoryGirl.create(:mix) }
let(:recording) { mix.recording }
before(:each) do
end
it "success" do
FactoryGirl.create(:quick_mix, user: recording.owner, recording:recording, autowire: false)
FactoryGirl.create(:quick_mix, user: recording.owner, recording: recording, autowire: false)
FactoryGirl.create(:recording_comment, recording: recording, user: recording.owner)
FactoryGirl.create(:recording_like, recording: recording, claimed_recording: recording.claimed_recordings.first, favorite:true)
FactoryGirl.create(:recording_like, recording: recording, claimed_recording: recording.claimed_recordings.first, favorite: true)
FactoryGirl.create(:playable_play, playable_id: recording.id, playable_type: 'JamRuby::Recording')
FactoryGirl.create(:recorded_video, user: recording.owner, recording: recording)
recording.reload
@ -1099,9 +1114,9 @@ describe Recording do
describe "add_timeline" do
let!(:recorded_jam_track_track) {FactoryGirl.create(:recorded_jam_track_track)}
let(:recording) {recorded_jam_track_track.recording}
let(:timeline_data) {{"sample" => "data"}}
let!(:recorded_jam_track_track) { FactoryGirl.create(:recorded_jam_track_track) }
let(:recording) { recorded_jam_track_track.recording }
let(:timeline_data) { {"sample" => "data"} }
let(:good_timeline) { {
"global" => {"recording_start_time" => 0, "jam_track_play_start_time" => 0, "jam_track_recording_start_play_offset" => 0},
"tracks" => [
@ -1111,7 +1126,7 @@ describe Recording do
"type" => "jam_track"
}
]
}
}
}
it "applies timeline data correctly" do

View File

@ -78,6 +78,18 @@ class ApiRecordingsController < ApiController
end
end
def create_immediately
@recording = Recording.create_immediately(current_user, params)
if @recording.errors.any?
response.status = :unprocessable_entity
respond_with @recording
else
respond_with @recording, responder: ApiResponder, :location => api_recordings_detail_url(@recording)
end
end
def start
music_session = ActiveMusicSession.find(params[:music_session_id])

View File

@ -8,8 +8,14 @@ class ArtifactsController < ApiController
if params[:type]
clients = clients.where("product ilike 'JamClient/#{params[:type]}'")
if params[:serialno]
Jamblaster.bootstrap(params[:serialno])
end
end
result = {}
clients.each do |client|

View File

@ -585,6 +585,8 @@ Rails.application.routes.draw do
match '/recordings/:id/timeline' => 'api_recordings#add_timeline', :via => :post, :as => 'api_recordings_timeline'
match '/recordings/:id/video_data' => 'api_recordings#add_video_data', :via => :post, :as => 'api_recordings_video_data'
match '/recordings/:id/video_data' => 'api_recordings#delete_video_data', :via => :delete, :as => 'api_recordings_video_data_delete'
match '/recordings' => 'api_recordings#create_immediately', :via => :post
# Recordings - recorded_tracks
match '/recordings/:id/tracks/:track_id' => 'api_recordings#show_recorded_track', :via => :get, :as => 'api_recordings_show_recorded_track'

View File

@ -14,44 +14,65 @@ describe "Artifact API ", :type => :api do
end
it "matches an artifact" do
get '/api/versioncheck.json', { :os=>'Win32', :product=>'JamClient'}
get '/api/versioncheck.json', {:os => 'Win32', :product => 'JamClient'}
last_response.status.should eql(200)
JSON.parse(last_response.body).should eql({ "version" => @artifact.version, "uri" => Rails.application.config.jam_admin_root_url + @artifact.uri.url, "size" => @artifact.size, "sha1" => @artifact.sha1})
JSON.parse(last_response.body).should eql({"version" => @artifact.version, "uri" => Rails.application.config.jam_admin_root_url + @artifact.uri.url, "size" => @artifact.size, "sha1" => @artifact.sha1})
end
it "matches no artifact" do
@artifact.delete
get '/api/versioncheck.json', { :os=>'Win32', :product=>'JamClient'}
get '/api/versioncheck.json', {:os => 'Win32', :product => 'JamClient'}
last_response.status.should eql(200)
JSON.parse(last_response.body).should eql({})
end
it "fails on bad product" do
it "fails on bad product" do
@artifact.delete
get '/api/versioncheck.json', { :os=>'what', :product=>'JamClient'}
get '/api/versioncheck.json', {:os => 'what', :product => 'JamClient'}
last_response.status.should eql(422)
JSON.parse(last_response.body).should eql({ "errors" => {"product" => ['not a valid product']}})
JSON.parse(last_response.body).should eql({"errors" => {"product" => ['not a valid product']}})
end
end
describe "client_downloads" do
before do
@win_client = FactoryGirl.create(:artifact_update, :product => 'JamClient/Win32')
@mac_client= FactoryGirl.create(:artifact_update, :product => 'JamClient/MacOSX')
describe "desktop" do
before do
@win_client = FactoryGirl.create(:artifact_update, :product => 'JamClient/Win32')
@mac_client= FactoryGirl.create(:artifact_update, :product => 'JamClient/MacOSX')
get '/api/artifacts/clients.json'
last_response.status.should eql(200)
@response = JSON.parse(last_response.body)
get '/api/artifacts/clients.json'
last_response.status.should eql(200)
@response = JSON.parse(last_response.body)
end
it {
@response.length.should == 2
@response[@mac_client.product]["size"].should == @mac_client.size
@response[@mac_client.product]["uri"].should_not be_nil
@response["JamClient/Win32"]["size"].should == @win_client.size
@response["JamClient/Win32"]["uri"].should_not be_nil
}
end
describe "jamblaster" do
before do
@jb_client = FactoryGirl.create(:artifact_update, :product => 'JamClient/JamBlaster')
get '/api/artifacts/JamBlaster.json', {serialno: 'abcde'}
last_response.status.should eql(200)
@response = JSON.parse(last_response.body)
end
it {
@response.length.should == 1
@response['JamBlaster']["size"].should == @jb_client.size
@response['JamBlaster']["uri"].should_not be_nil
Jamblaster.find_by_serial_no('abcde').should_not be_nil
}
end
it {
@response.length.should == 2
@response[@mac_client.product]["size"].should == @mac_client.size
@response[@mac_client.product]["uri"].should_not be_nil
@response["JamClient/Win32"]["size"].should == @win_client.size
@response["JamClient/Win32"]["uri"].should_not be_nil
}
end
end

View File

@ -771,7 +771,7 @@ module JamWebsockets
# we have to deal with jamblaster before login
if jamblaster_serial_no && jamblaster_serial_no != ''
jamblaster = Jamblaster.find_by_serial_no(jamblaster_serial_no)
jamblaster = Jamblaster.bootstrap(jamblaster_serial_no)
if jamblaster
client.is_jamblaster = true
end