diff --git a/db/manifest b/db/manifest index b0f8b2ae1..b17be0ac5 100755 --- a/db/manifest +++ b/db/manifest @@ -238,3 +238,4 @@ jam_track_updates.sql private_key_in_jam_track_rights.sql jam_track_tap_in.sql jam_track_available.sql +active_jam_track.sql diff --git a/db/up/active_jam_track.sql b/db/up/active_jam_track.sql new file mode 100644 index 000000000..16934aa5b --- /dev/null +++ b/db/up/active_jam_track.sql @@ -0,0 +1,2 @@ +ALTER TABLE active_music_sessions ADD COLUMN jam_track_id BIGINT; +ALTER TABLE active_music_sessions ADD COLUMN jam_track_initiator_id VARCHAR(64); \ No newline at end of file diff --git a/ruby/lib/jam_ruby/constants/validation_messages.rb b/ruby/lib/jam_ruby/constants/validation_messages.rb index 7dc4d955a..c24ca07ce 100644 --- a/ruby/lib/jam_ruby/constants/validation_messages.rb +++ b/ruby/lib/jam_ruby/constants/validation_messages.rb @@ -80,6 +80,8 @@ module ValidationMessages MUST_BE_A_MUSICIAN = "must be a musician" CLAIMED_RECORDING_ALREADY_IN_PROGRESS = "already started by someone else" MUST_BE_KNOWN_TIMEZONE = "not valid" + JAM_TRACK_ALREADY_OPEN = 'another jam track already open' + RECORDING_ALREADY_IN_PROGRESS = "recording being made" # notification DIFFERENT_SOURCE_TARGET = 'can\'t be same as the sender' diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb index dd244ab68..6dd93acc8 100644 --- a/ruby/lib/jam_ruby/models/active_music_session.rb +++ b/ruby/lib/jam_ruby/models/active_music_session.rb @@ -7,11 +7,14 @@ module JamRuby self.table_name = 'active_music_sessions' - attr_accessor :legal_terms, :max_score + attr_accessor :legal_terms, :max_score, :opening_jam_track, :opening_recording belongs_to :claimed_recording, :class_name => "JamRuby::ClaimedRecording", :foreign_key => "claimed_recording_id", :inverse_of => :playing_sessions belongs_to :claimed_recording_initiator, :class_name => "JamRuby::User", :inverse_of => :playing_claimed_recordings, :foreign_key => "claimed_recording_initiator_id" + belongs_to :jam_track, :class_name => "JamRuby::JamTrack", :foreign_key => "jam_track_id", :inverse_of => :playing_sessions + belongs_to :jam_track_initiator, :class_name => "JamRuby::User", :inverse_of => :playing_jam_tracks, :foreign_key => "jam_track_initiator_id" + has_one :music_session, :class_name => "JamRuby::MusicSession", :foreign_key => 'music_session_id' has_one :mount, :class_name => "JamRuby::IcecastMount", :inverse_of => :music_session, :foreign_key => 'music_session_id' belongs_to :creator, :class_name => 'JamRuby::User', :foreign_key => :user_id @@ -22,7 +25,8 @@ module JamRuby has_many :chats, :class_name => "JamRuby::ChatMessages", :foreign_key => "session_id" validates :creator, :presence => true validate :creator_is_musician - validate :no_new_playback_while_playing + validate :validate_opening_recording, :if => :opening_recording + validate :validate_opening_jam_track, :if => :opening_jam_track after_create :started_session @@ -61,12 +65,30 @@ module JamRuby end end - def no_new_playback_while_playing - # if we previous had a claimed recording and are trying to set one - # and if also the previous initiator is different than the current one... it's a no go - if !claimed_recording_id_was.nil? && !claimed_recording_id.nil? && - claimed_recording_initiator_id_was != claimed_recording_initiator_id - errors.add(:claimed_recording, ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS) + def validate_opening_recording + unless claimed_recording_id_was.nil? + errors.add(:claimed_recording, ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS) + end + + if is_jam_track_open? + errors.add(:claimed_recording, ValidationMessages::JAM_TRACK_ALREADY_OPEN) + end + end + + def validate_opening_jam_track + # validate that there is no jam track already open in this session + unless jam_track_id_was.nil? + errors.add(:jam_track, ValidationMessages::JAM_TRACK_ALREADY_OPEN) + end + + # validate that there is no recording being made + if is_recording? + errors.add(:jam_track, ValidationMessages::RECORDING_ALREADY_IN_PROGRESS) + end + + # validate that there is no recording being played back to the session + if is_playing_recording? + errors.add(:jam_track, ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS) end end @@ -572,6 +594,10 @@ module JamRuby recordings.where(:music_session_id => self.id).order('created_at desc').limit(1).first end + def is_jam_track_open? + !self.jam_track.nil? + end + # is this music session currently recording? def is_recording? recordings.where(:duration => nil).count > 0 @@ -594,7 +620,9 @@ module JamRuby def claimed_recording_start(owner, claimed_recording) self.claimed_recording = claimed_recording self.claimed_recording_initiator = owner + self.opening_recording = true self.save + self.opening_recording = false end def claimed_recording_stop @@ -705,6 +733,19 @@ module JamRuby GoogleAnalyticsEvent.track_band_real_session(self) end + def open_jam_track(user, jam_track) + self.jam_track = jam_track + self.jam_track_initiator = user + self.opening_jam_track = true + self.save + self.opening_jam_track = false + end + + def close_jam_track + self.jam_track = nil + self.jam_track_initiator = nil + self.save + end def self.sync(session_history) music_session = MusicSession.find_by_id(session_history.id) diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index 89117323e..415d3f036 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -50,6 +50,8 @@ module JamRuby has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight" #, inverse_of: 'jam_track', :foreign_key => "jam_track_id" has_many :owners, :through => :jam_track_rights, :class_name => "JamRuby::User", :source => :user + has_many :playing_sessions, :class_name => "JamRuby::ActiveMusicSession" + accepts_nested_attributes_for :jam_track_tracks, allow_destroy: true accepts_nested_attributes_for :jam_track_tap_ins, allow_destroy: true diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index c35db3dd2..a5ea8b827 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -65,6 +65,7 @@ module JamRuby has_many :recordings, :through => :claimed_recordings, :class_name => "JamRuby::Recording" has_many :claimed_recordings, :class_name => "JamRuby::ClaimedRecording", :inverse_of => :user has_many :playing_claimed_recordings, :class_name => "JamRuby::ActiveMusicSession", :inverse_of => :claimed_recording_initiator + has_many :playing_jam_tracks, :class_name => "JamRuby::ActiveMusicSession", :inverse_of => :jam_track_initiator # self.id = user_id in likes table has_many :likings, :class_name => "JamRuby::Like", :inverse_of => :user, :dependent => :destroy diff --git a/ruby/spec/jam_ruby/models/active_music_session_spec.rb b/ruby/spec/jam_ruby/models/active_music_session_spec.rb index ac0288f23..392d70473 100644 --- a/ruby/spec/jam_ruby/models/active_music_session_spec.rb +++ b/ruby/spec/jam_ruby/models/active_music_session_spec.rb @@ -580,6 +580,78 @@ describe ActiveMusicSession do music_session.is_recording?.should be_false end + + describe "open_jam_track" do + before(:each) do + @user1 = FactoryGirl.create(:user) + @connection = FactoryGirl.create(:connection, :user => @user1) + @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') + @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) + @music_session = FactoryGirl.create(:active_music_session, :creator => @user1, :musician_access => true) + # @music_session.connections << @connection + @music_session.save! + @connection.join_the_session(@music_session, true, nil, @user1, 10) + @jam_track = FactoryGirl.create(:jam_track) + @jam_track_right = FactoryGirl.create(:jam_track_right, jam_track: @jam_track, user: @user1) + end + + it "allow a jam track to be associated" do + # simple success case; just open the jam track and observe the state of the session is correct + @music_session.open_jam_track(@user1, @jam_track) + @music_session.errors.any?.should be_false + @music_session.reload + @music_session.jam_track.should == @jam_track + @music_session.jam_track_initiator.should == @user1 + end + + it "allow a jam track to be closed" do + # simple success case; close an opened jam track and observe the state of the session is correct + @music_session.open_jam_track(@user1, @jam_track) + @music_session.errors.any?.should be_false + @music_session.close_jam_track + @music_session.errors.any?.should be_false + @music_session.reload + @music_session.jam_track.should be_nil + @music_session.jam_track_initiator.should be_nil + end + + it "disallow a jam track to be opened when another is already opened" do + # if a jam track is open, don't allow another to be opened + @music_session.open_jam_track(@user1, @jam_track) + @music_session.errors.any?.should be_false + @music_session.open_jam_track(@user1, @jam_track) + @music_session.errors.any?.should be_true + @music_session.errors[:jam_track] == [ValidationMessages::JAM_TRACK_ALREADY_OPEN] + end + + it "disallow a jam track to be opened when recording is ongoing" do + @recording = Recording.start(@music_session, @user1) + @music_session.errors.any?.should be_false + @music_session.open_jam_track(@user1, @jam_track) + @music_session.errors.any?.should be_true + @music_session.errors[:jam_track] == [ValidationMessages::RECORDING_ALREADY_IN_PROGRESS] + end + + it "disallow a jam track to be opened when recording is playing back" do + # create a recording, and open it for play back + @recording = Recording.start(@music_session, @user1) + @recording.errors.any?.should be_false + @recording.stop + @recording.reload + @claimed_recording = @recording.claim(@user1, "name", "description", Genre.first, true) + @claimed_recording.errors.any?.should be_false + @music_session.claimed_recording_start(@user1, @claimed_recording) + @music_session.errors.any?.should be_false + + # while it's open, try to open a jam track + @music_session.open_jam_track(@user1, @jam_track) + @music_session.errors.any?.should be_true + @music_session.errors[:jam_track] == [ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS] + end + + end + + describe "recordings" do before(:each) do @@ -613,7 +685,7 @@ describe ActiveMusicSession do end end - describe "claim a recording" do + describe "open a recording" do before(:each) do @recording = Recording.start(@music_session, @user1) @@ -651,13 +723,27 @@ describe ActiveMusicSession do @music_session.errors[:claimed_recording] == [ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS] end - it "allow a claimed recording to be started when already started by self" do + it "disallow a claimed recording to be started when already started by self" do @user2 = FactoryGirl.create(:user) @claimed_recording2 = @recording.claim(@user1, "name", "description", Genre.first, true) @music_session.claimed_recording_start(@user1, @claimed_recording) @music_session.errors.any?.should be_false @music_session.claimed_recording_start(@user1, @claimed_recording2) + @music_session.errors.any?.should be_true + end + + it "disallow a claimed recording to be started when jam track is open" do + # open the jam track + @jam_track = FactoryGirl.create(:jam_track) + @jam_track_right = FactoryGirl.create(:jam_track_right, jam_track: @jam_track, user: @user1) + @music_session.open_jam_track(@user1, @jam_track) @music_session.errors.any?.should be_false + + # and try to open a recording for playback + @music_session.claimed_recording_start(@user1, @claimed_recording) + @music_session.errors.any?.should be_true + @music_session.errors[:claimed_recording] == [ValidationMessages::JAM_TRACK_ALREADY_OPEN] + end end end diff --git a/ruby/spec/jam_ruby/models/email_batch_spec.rb b/ruby/spec/jam_ruby/models/email_batch_spec.rb index 6ff87e980..fe120100d 100644 --- a/ruby/spec/jam_ruby/models/email_batch_spec.rb +++ b/ruby/spec/jam_ruby/models/email_batch_spec.rb @@ -5,7 +5,11 @@ describe EmailBatch do before(:all) do User.delete_all end +<<<<<<< HEAD +======= + +>>>>>>> feature/activejamtrack after(:each) do Timecop.return end diff --git a/ruby/spec/jam_ruby/models/music_session_spec.rb b/ruby/spec/jam_ruby/models/music_session_spec.rb index a1d22d324..6273855d9 100644 --- a/ruby/spec/jam_ruby/models/music_session_spec.rb +++ b/ruby/spec/jam_ruby/models/music_session_spec.rb @@ -241,7 +241,7 @@ describe MusicSession do @music_session.claimed_recording_start(@user1, @claimed_recording) @music_session.errors.any?.should be_false @music_session.claimed_recording_start(@user1, @claimed_recording2) - @music_session.errors.any?.should be_false + @music_session.errors.any?.should be_true end end end diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index d7e70a6b3..b85f265d0 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -4,7 +4,7 @@ class ApiMusicSessionsController < ApiController # have to be signed in currently to see this screen before_filter :api_signed_in_user, :except => [ :add_like, :show, :show_history, :add_session_info_comment ] - before_filter :lookup_session, only: [:show, :update, :delete, :claimed_recording_start, :claimed_recording_stop, :track_sync] + before_filter :lookup_session, only: [:show, :update, :delete, :claimed_recording_start, :claimed_recording_stop, :track_sync, :jam_track_open, :jam_track_close] skip_before_filter :api_signed_in_user, only: [:perf_upload] respond_to :json @@ -570,6 +570,34 @@ class ApiMusicSessionsController < ApiController end end + + def jam_track_open + unless @music_session.users.exists?(current_user) + raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end + + @jam_track = JamTrack.find(params[:jam_track_id]) + + unless @jam_track.right_for_user(current_user) + raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end + + @music_session.open_jam_track(current_user, @jam_track) + + respond_with_model(@music_session) + end + + def jam_track_close + unless @music_session.users.exists?(current_user) + raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end + + @music_session.close_jam_track + + respond_with_model(@music_session) + end + + private def lookup_session diff --git a/web/app/views/api_music_sessions/close_jam_track.rabl b/web/app/views/api_music_sessions/close_jam_track.rabl new file mode 100644 index 000000000..2128cad8c --- /dev/null +++ b/web/app/views/api_music_sessions/close_jam_track.rabl @@ -0,0 +1,4 @@ +object @music_session + + +attributes :id \ No newline at end of file diff --git a/web/app/views/api_music_sessions/open_jam_track.rabl b/web/app/views/api_music_sessions/open_jam_track.rabl new file mode 100644 index 000000000..f79061b5b --- /dev/null +++ b/web/app/views/api_music_sessions/open_jam_track.rabl @@ -0,0 +1,3 @@ +object @music_session + +attributes :id \ No newline at end of file diff --git a/web/app/views/api_music_sessions/show.rabl b/web/app/views/api_music_sessions/show.rabl index f78b7934a..658e43d9e 100644 --- a/web/app/views/api_music_sessions/show.rabl +++ b/web/app/views/api_music_sessions/show.rabl @@ -68,8 +68,20 @@ else } } - # only show currently playing recording data if the current_user is in the session + # only show currently open jam track info if the current user is in the session + child({:jam_track => :jam_track}, :if => lambda { |music_session| music_session.users.exists?(current_user) }) { + attributes :id, :name, :description, :bpm, :initial_play_silence, :tap_in_count + child(:jam_track_tracks => :tracks) { + attributes :id, :part, :instrument + } + + child(:jam_track_tap_ins => :tap_ins) { + attributes :offset_time + } + } + + # only show currently playing recording data if the current_user is in the session child({:claimed_recording => :claimed_recording}, :if => lambda { |music_session| music_session.users.exists?(current_user) }) { attributes :id, :name, :description, :is_public diff --git a/web/config/routes.rb b/web/config/routes.rb index 962c18c62..e0642c69d 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -175,8 +175,9 @@ SampleApp::Application.routes.draw do match '/sessions/:id/comments' => 'api_music_sessions#add_comment', :via => :post match '/sessions/:id/likes' => 'api_music_sessions#add_like', :via => :post match '/sessions/:id/history' => 'api_music_sessions#show_history', :via => :get, :as => 'api_session_history_detail' - match '/sessions/:id/details/comments' => 'api_music_sessions#add_session_info_comment', :via => :post + match '/sessions/:id/jam_tracks/:jam_track_id/open' => 'api_music_sessions#jam_track_open', :via => :post + match '/sessions/:id/jam_tracks/close' => 'api_music_sessions#jam_track_close', :via => :post # music session tracks match '/sessions/:id/tracks' => 'api_music_sessions#track_create', :via => :post diff --git a/web/spec/controllers/api_music_sessions_controller_spec.rb b/web/spec/controllers/api_music_sessions_controller_spec.rb index e981e7e63..eab77192b 100644 --- a/web/spec/controllers/api_music_sessions_controller_spec.rb +++ b/web/spec/controllers/api_music_sessions_controller_spec.rb @@ -166,4 +166,61 @@ describe ApiMusicSessionsController do end end + + describe "open_jam_track" do + + let(:ams) { FactoryGirl.create(:active_music_session, creator: user) } + let(:jam_track) { FactoryGirl.create(:jam_track)} + + it "does not allow someone to open a track unless they are in the session" do + post :jam_track_open, {:format => 'json', id: ams.id, jam_track_id: jam_track.id} + response.status.should == 403 + end + + it "does not allow someone to open a track unless they own the jam track" do + conn.join_the_session(ams.music_session, true, tracks, user, 10) + + post :jam_track_open, {:format => 'json', id: ams.id, jam_track_id: jam_track.id} + response.status.should == 403 + end + + it "allows someone who owns the jam track to open it" do + # put the connection of the user into the session, so th + conn.join_the_session(ams.music_session, true, tracks, user, 10) + FactoryGirl.create(:jam_track_right, jam_track: jam_track, user: user) + + post :jam_track_open, {:format => 'json', id: ams.id, jam_track_id: jam_track.id} + response.status.should == 200 + end + + it "does not allow someone to close a track unless they are in the session" do + post :jam_track_close, {:format => 'json', id: ams.id} + response.status.should == 403 + end + + it "allows the jam track to be closed" do + # put the connection of the user into the session, so th + conn.join_the_session(ams.music_session, true, tracks, user, 10) + FactoryGirl.create(:jam_track_right, jam_track: jam_track, user: user) + + post :jam_track_open, {:format => 'json', id: ams.id, jam_track_id: jam_track.id} + response.status.should == 200 + + post :jam_track_close, {:format => 'json', id: ams.id} + response.status.should == 200 + end + + it "show.rabl shows jam track info when open" do + conn.join_the_session(ams.music_session, true, tracks, user, 10) + FactoryGirl.create(:jam_track_right, jam_track: jam_track, user: user) + post :jam_track_open, {:format => 'json', id: ams.id, jam_track_id: jam_track.id} + + # check the show.rabl for jam_track info + get :show, {:format => 'json', id: ams.id} + json = JSON.parse(response.body, :symbolize_names => true) + + json[:jam_track].should_not be_nil + json[:jam_track][:id].should == jam_track.id + end + end end