diff --git a/admin/app/models/cohort.rb b/admin/app/models/cohort.rb index 29523a46d..78751305d 100644 --- a/admin/app/models/cohort.rb +++ b/admin/app/models/cohort.rb @@ -150,8 +150,9 @@ SELECT played.player_id FROM WHERE pp.created_at >= '#{start_date}' AND pp.created_at <= '#{end_date}' AND - pp.playable_type = 'JamRuby::JamTrack' - GROUP BY player_id + pp.jam_track_id IS NOT NULL /* VRFS-2916 jam_tracks.id is varchar: REMOVE */ + /* pp.playable_type = 'JamRuby::JamTrack' */ /* VRFS-2916 jam_tracks.id is varchar: ADD */ + GROUP BY player_id ) played WHERE #{where} SQL @@ -168,7 +169,10 @@ WHERE tt.created_at >= '#{start_date}' AND tt.created_at <= '#{end_date}' SQL - yield(sql) if block_given? + if block_given? + yield_sql = yield(sql) + sql = yield_sql unless yield_sql.blank? + end self.class.cohort_users(self).where("users.id IN (#{sql})").count end @@ -196,12 +200,12 @@ SQL _put_data_set(assoc_key, count, num_user) count = _subquery(assoc_key = :jam_track_rights, num_user) do |subsql| - subsql += " AND tt.redeemed = 'f' " + subsql += " AND tt.is_test_purchase = 'f' AND tt.redeemed = 'f' " end _put_data_set(assoc_key, count, num_user) count = _subquery(assoc_key = :jam_track_rights, num_user) do |subsql| - subsql += " AND tt.redeemed = 't' " + subsql += " AND tt.is_test_purchase = 'f' AND tt.redeemed = 't' " end _put_data_set(:jam_track_rights_redeemed, count, num_user) @@ -235,13 +239,6 @@ SQL self.save! end - def _join_user_all_time(assoc_ref) - assoc_ref.active_record - .joins("INNER JOIN users AS uu ON uu.id = #{assoc_ref.foreign_key}") - .where(created_at: self.group_start..self.group_end) - .where(['uu.created_at >= ? AND uu.created_at <= ?', self.group_start, self.group_end]) - end - def _all_time! unless 0 < num_user = self.class.cohort_users(self).count self.update_attribute(:data_set, {}) @@ -270,11 +267,16 @@ SQL count = _subquery(assoc_key = :friendships, num_user) _put_data_set(assoc_key, count, num_user) - count = _subquery(assoc_key = :jam_track_rights, num_user) + count = _subquery(assoc_key = :jam_track_rights, num_user) do |subsql| + subsql += " AND tt.is_test_purchase = 'f'" + end _put_data_set(assoc_key, count, num_user) - + count = _subquery(assoc_key = :jam_tracks_played, num_user) do |subsql| - subsql += " AND tt.playable_type = 'JamRuby::JamTrack' " + # VRFS-2916 jam_tracks.id is varchar: REMOVE + subsql += " AND tt.jam_track_id IS NOT NULL " + # VRFS-2916 jam_tracks.id is varchar: ADD + # subsql += " AND tt.playable_type = 'JamRuby::JamTrack' " end _put_data_set(assoc_key, count, num_user) diff --git a/db/manifest b/db/manifest index 46d675065..dbc9dc3a0 100755 --- a/db/manifest +++ b/db/manifest @@ -265,5 +265,6 @@ connection_metronome.sql preview_jam_track_tracks.sql cohorts.sql jam_track_right_admin_purchase.sql +jam_track_playable_plays.sql shopping_cart_anonymous.sql -user_reuse_card_and_reedem.sql +user_reuse_card_and_reedem.sql \ No newline at end of file diff --git a/db/up/jam_track_playable_plays.sql b/db/up/jam_track_playable_plays.sql new file mode 100644 index 000000000..dfa95d07d --- /dev/null +++ b/db/up/jam_track_playable_plays.sql @@ -0,0 +1,6 @@ +ALTER TABLE playable_plays ADD COLUMN jam_track_id bigint; +ALTER TABLE playable_plays ALTER COLUMN playable_id DROP NOT NULL; +ALTER TABLE playable_plays ALTER COLUMN playable_type DROP NOT NULL; + + + diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index f4d2838e8..49dfcd4b5 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -47,13 +47,19 @@ module JamRuby has_many :jam_track_tracks, :class_name => "JamRuby::JamTrackTrack", order: 'position ASC' has_many :jam_track_tap_ins, :class_name => "JamRuby::JamTrackTapIn", order: 'offset_time ASC' - has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight" #, inverse_of: 'jam_track', :foreign_key => "jam_track_id" + 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" has_many :recordings, :class_name => "JamRuby::Recording" + # VRFS-2916 jam_tracks.id is varchar: REMOVE + has_many :plays, :class_name => "JamRuby::PlayablePlay", :foreign_key => :jam_track_id, :dependent => :destroy + # VRFS-2916 jam_tracks.id is varchar: ADD + # has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy + 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/playable_play.rb b/ruby/lib/jam_ruby/models/playable_play.rb index 4631bc4db..148e672ea 100644 --- a/ruby/lib/jam_ruby/models/playable_play.rb +++ b/ruby/lib/jam_ruby/models/playable_play.rb @@ -2,9 +2,27 @@ module JamRuby class PlayablePlay < ActiveRecord::Base self.table_name = "playable_plays" - belongs_to :playable, :polymorphic => :true, :counter_cache => :play_count + belongs_to :playable, :polymorphic => :true + # VRFS-2916 jam_tracks.id is varchar: REMOVE + belongs_to :jam_track, :foreign_key => :jam_track_id belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "player_id" belongs_to :claimed_recording, :class_name => "JamRuby::ClaimedRecording", :foreign_key => "claimed_recording_id" + validate do + # VRFS-2916 jam_tracks.id is varchar: REMOVE + if !playable_id && !jam_track_id + self.errors[:base] << 'No playable instance detected' + end + + # VRFS-2916 jam_tracks.id is varchar: ADD + # if !playable_id + # self.errors[:base] << 'No playable instance detected' + # end + + if !user + self.errors[:base] << 'No user detected' + end + end + end end diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 8b8b3deed..fc725c59b 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -71,6 +71,11 @@ module JamRuby 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 + # VRFS-2916 jam_tracks.id is varchar: REMOVE + has_many :jam_tracks_played, :class_name => "JamRuby::PlayablePlay", :foreign_key => 'player_id', :conditions => "jam_track_id IS NOT NULL" + # VRFS-2916 jam_tracks.id is varchar: ADD + # has_many :jam_tracks_played, :class_name => "JamRuby::PlayablePlay", :foreign_key => 'player_id', :conditions => ["playable_type = 'JamRuby::JamTrack'"] + # 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/jam_track_spec.rb b/ruby/spec/jam_ruby/models/jam_track_spec.rb index 063f3a029..d03cf13fe 100644 --- a/ruby/spec/jam_ruby/models/jam_track_spec.rb +++ b/ruby/spec/jam_ruby/models/jam_track_spec.rb @@ -14,6 +14,30 @@ describe JamTrack do jam_track.licensor.jam_tracks.should == [jam_track] end + describe 'plays' do + it "creates played instance properly" do + @jam_track = FactoryGirl.create(:jam_track) + play = PlayablePlay.new + + # VRFS-2916 jam_tracks.id is varchar: REMOVE + play.jam_track = @jam_track + # VRFS-2916 jam_tracks.id is varchar: ADD + # play.playable = @jam_track + + play.user = user + play.save! + expect(@jam_track.plays.count).to eq(1) + expect(@jam_track.plays[0].user.id).to eq(user.id) + expect(user.jam_tracks_played.count).to eq(1) + end + it "handles played errors" do + play = PlayablePlay.new + play.user = user + play.save + expect(play.errors.count).to eq(1) + end + end + describe "index" do it "empty query" do query, pager = JamTrack.index({}, user) diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 0eda8f103..624e81ea1 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -1222,6 +1222,15 @@ }) } + function playJamTrack(jamTrackId) { + return $.ajax({ + type: "POST", + url: '/api/jamtracks/played/' + jamTrackId, + dataType: "json", + contentType: 'application/json' + }); + } + function closeJamTrack(options) { var musicSessionId = options["id"]; delete options["id"]; @@ -1745,6 +1754,7 @@ this.validateUrlSite = validateUrlSite; this.markRecordedBackingTrackSilent = markRecordedBackingTrackSilent; this.addRecordingTimeline = addRecordingTimeline; + this.playJamTrack = playJamTrack; return this; }; diff --git a/web/app/assets/javascripts/jquery.listenbroadcast.js b/web/app/assets/javascripts/jquery.listenbroadcast.js index 059b7c18b..f6964cd60 100644 --- a/web/app/assets/javascripts/jquery.listenbroadcast.js +++ b/web/app/assets/javascripts/jquery.listenbroadcast.js @@ -74,6 +74,9 @@ var playState = PlayStateNone; // tracks if the stream is actually playing + var CANNOT_BROADCAST_TITLE = 'Unable to Broadcast Session'; + var CANNOT_BROADCAST_MSG = 'This session cannot be broadcasted. The session organizer may have configured it to be private.'; + function play(e) { if(e) { e.preventDefault(); @@ -407,17 +410,21 @@ sessionInfo = response; }) .fail(function(jqXHR) { - if(jqXHR.status == 404 || jqXHR.status == 403) { + if(jqXHR.status == 404) { transition(PlayStateSessionOver); destroy(); } + else if (jqXHR.status == 403) { + logger.debug("session is private"); + context.JK.app.notify({"title": CANNOT_BROADCAST_TITLE, "text": CANNOT_BROADCAST_MSG}); + } else if(jqXHR.status >= 500 && jqXHR.status <= 599){ transition(PlayStateServerError); } else { transition(PlayStateNetworkError); } - }) + }); } function triggerStateChange() { @@ -702,28 +709,31 @@ } function openBubble() { - checkServer().done(function(response) { + checkServer() + .done(function(response) { - var mountId = sessionInfo.mount ? sessionInfo.mount.id : null; + var mountId = sessionInfo.mount ? sessionInfo.mount.id : null; - if(mountId) { - rest.getMount({id: mountId}) - .done(function (mount) { - mountInfo = mount; - $parent.data('mount-id', mountId); - context.JK.SubscriptionUtils.subscribe('mount', mountId).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, onDetailEvent); - $parent.btOn(); - }) - .fail(context.JK.app.ajaxError) - } - else { - mountInfo = null; - destroy(); - context.JK.app.notify({"title": "Unable to Broadcast Session", "text": "This session cannot be broadcasted. The session organizer may have configured it to be private."}); - } - }) - .fail(function() { - logger.debug("session is over") + if(mountId) { + rest.getMount({id: mountId}) + .done(function (mount) { + mountInfo = mount; + $parent.data('mount-id', mountId); + context.JK.SubscriptionUtils.subscribe('mount', mountId).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, onDetailEvent); + $parent.btOn(); + }) + .fail(context.JK.app.ajaxError) + } + else { + mountInfo = null; + destroy(); + context.JK.app.notify({"title": CANNOT_BROADCAST_TITLE, "text": CANNOT_BROADCAST_MSG}); + } + }) + .fail(function(response) { + if (response.status == 404) { + logger.debug("session is over"); + } }) } diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index d457425d7..5aa7ac747 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -2557,6 +2557,8 @@ { title: "JamTrack Can Not Open", text: "Unable to open your JamTrack. Please contact support@jamkazam.com" }, null, true); + } else { + rest.playJamTrack(jamTrack.id); } } }) diff --git a/web/app/controllers/api_jam_tracks_controller.rb b/web/app/controllers/api_jam_tracks_controller.rb index 662f44057..5be70e52f 100644 --- a/web/app/controllers/api_jam_tracks_controller.rb +++ b/web/app/controllers/api_jam_tracks_controller.rb @@ -14,6 +14,28 @@ class ApiJamTracksController < ApiController render "api_jam_tracks/index", :layout => nil end + def played + if params[:id].blank? + render(:json => { :message => "JamTrack ID required" }, :status => 400) and return + end + play = PlayablePlay.new + play.player_id = current_user.id + play.ip_address = request.remote_ip + + # VRFS-2916 jam_tracks.id is varchar: REMOVE + play.jam_track = JamTrack.where(id: params[:id].to_i).first + # VRFS-2916 jam_tracks.id is varchar: ADD + # play.playable = JamTrack.where(id: params[:id]).first + + play.save + + if play.errors.any? + render :json => { :message => "Unexpected error occurred" }, :status => 500 + else + render :json => {}, :status => 201 + end + end + def purchased params[:show_purchased_only] = true data = JamTrack.index(params, current_user) diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index bb8760dc2..6fb5df5cf 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -165,7 +165,8 @@ class ApiMusicSessionsController < ApiController def show unless @music_session.can_see? current_user - raise ActiveRecord::RecordNotFound + # render :json => { :message => ValidationMessages::PERMISSION_VALIDATION_ERROR }, :status => 403 + raise JamRuby::PermissionError end end diff --git a/web/config/routes.rb b/web/config/routes.rb index d21ed3861..b50dae134 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -207,6 +207,7 @@ SampleApp::Application.routes.draw do match '/jamtracks' => 'api_jam_tracks#index', :via => :get, :as => 'api_jam_tracks_list' match '/jamtracks/purchased' => 'api_jam_tracks#purchased', :via => :get, :as => 'api_jam_tracks_purchased' match '/jamtracks/download/:id' => 'api_jam_tracks#download', :via => :get, :as => 'api_jam_tracks_download' + match '/jamtracks/played/:id' => 'api_jam_tracks#played', :via => :post, :as => 'api_jam_tracks_played' match '/jamtracks/enqueue/:id' => 'api_jam_tracks#enqueue', :via => :post, :as => 'api_jam_tracks_enqueue' match '/jamtracks/rights/:id' => 'api_jam_tracks#show_jam_track_right', :via => :get, :as => 'api_jam_tracks_show_right' match '/jamtracks/keys' => 'api_jam_tracks#keys', :via => :post, :as => 'api_jam_tracks_keys' diff --git a/web/spec/controllers/api_jam_tracks_controller_spec.rb b/web/spec/controllers/api_jam_tracks_controller_spec.rb index baeb7d1e3..5d9ec8c59 100644 --- a/web/spec/controllers/api_jam_tracks_controller_spec.rb +++ b/web/spec/controllers/api_jam_tracks_controller_spec.rb @@ -94,6 +94,30 @@ describe ApiJamTracksController do end end + describe "jamtrack plays" do + it "handle api call success" do + post :played, { id: @jam_track.id, user: @user } + expect(response.status).to eq(201) + json = JSON.parse(response.body) + expect(json.length).to eq(0) + end + + it "handle api call 400" do + post :played, { user: @user } + expect(response.status).to eq(400) + json = JSON.parse(response.body) + expect(/JamTrack ID required/).to match(json['message']) + end + + it "handle api call 500" do + post :played, { id: 999, user: @user } + expect(response.status).to eq(500) + json = JSON.parse(response.body) + expect(/Unexpected error occurred/).to match(json['message']) + end + + end + describe "with a JamTrack" do before(:each) do JamTrackRight.destroy_all