diff --git a/db/manifest b/db/manifest index 6d546452d..f0f8fe03f 100755 --- a/db/manifest +++ b/db/manifest @@ -114,4 +114,5 @@ feed_autoincrement_primary_key.sql music_sessions_plays.sql plays_likes_counters.sql add_upright_bass.sql -music_session_history_public.sql \ No newline at end of file +music_session_history_public.sql +track_claimed_recording.sql \ No newline at end of file diff --git a/db/up/track_claimed_recording.sql b/db/up/track_claimed_recording.sql new file mode 100644 index 000000000..ca3fc62bc --- /dev/null +++ b/db/up/track_claimed_recording.sql @@ -0,0 +1,3 @@ +ALTER TABLE recordings_likers ADD COLUMN claimed_recording_id VARCHAR(64) NOT NULL REFERENCES claimed_recordings(id); +ALTER TABLE recordings_plays ADD COLUMN claimed_recording_id VARCHAR(64) NOT NULL REFERENCES claimed_recordings(id); +ALTER TABLE recordings_likers ADD COLUMN favorite BOOLEAN NOT NULL DEFAULT TRUE; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/claimed_recording.rb b/ruby/lib/jam_ruby/models/claimed_recording.rb index 13870f433..bf01c096d 100644 --- a/ruby/lib/jam_ruby/models/claimed_recording.rb +++ b/ruby/lib/jam_ruby/models/claimed_recording.rb @@ -3,13 +3,14 @@ module JamRuby attr_accessible :name, :description, :is_public, :is_downloadable, :genre_id, :recording_id, :user_id, as: :admin - belongs_to :recording, :class_name => "JamRuby::Recording", :inverse_of => :claimed_recordings, :foreign_key => 'recording_id' - belongs_to :user, :class_name => "JamRuby::User", :inverse_of => :claimed_recordings - belongs_to :genre, :class_name => "JamRuby::Genre" - has_many :recorded_tracks, :through => :recording, :class_name => "JamRuby::RecordedTrack" - has_many :playing_sessions, :class_name => "JamRuby::MusicSession" - has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id' - + belongs_to :recording, :class_name => "JamRuby::Recording", :inverse_of => :claimed_recordings, :foreign_key => 'recording_id' + belongs_to :user, :class_name => "JamRuby::User", :inverse_of => :claimed_recordings + belongs_to :genre, :class_name => "JamRuby::Genre" + has_many :recorded_tracks, :through => :recording, :class_name => "JamRuby::RecordedTrack" + has_many :playing_sessions, :class_name => "JamRuby::MusicSession" + has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "claimed_recording_id" + has_many :plays, :class_name => "JamRuby::RecordingPlay", :foreign_key => "claimed_recording_id" + has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id' validates :name, no_profanity: true, length: {minimum: 3, maximum: 64}, presence: true validates :description, no_profanity: true, length: {maximum: 8000} @@ -23,6 +24,7 @@ module JamRuby before_create :generate_share_token SHARE_TOKEN_LENGTH = 8 + FIXNUM_MAX = (2**(0.size * 8 -2) -1) def user_belongs_to_recording @@ -72,6 +74,50 @@ module JamRuby token.gsub(/[^0-9A-Za-z]/, '') end + # right now, the only thing that is brought back is ClaimedRecordings, and you can only query your own favorites + def self.index_favorites(user, params = {}) + limit = params[:limit] + limit ||= 20 + limit = limit.to_i + + # validate sort + sort = params[:sort] + sort ||= 'date' + raise "not valid sort #{sort}" unless sort == "date" + + start = params[:start].presence + start ||= 0 + start = start.to_i + + + type_filter = params[:type] + type_filter ||= 'claimed_recording' + raise "not valid type #{type_filter}" unless type_filter == "claimed_recording" + + target_user = params[:user] + + raise PermissionError, "must specify current user" unless user + raise "user must be specified" unless target_user + + if target_user != user.id + raise PermissionError, "unable to view another user's favorites" + end + + query = ClaimedRecording.limit(limit).order('created_at DESC').offset(start) + query = query.joins(:likes) + query = query.where('favorite = true') + query = query.where("recordings_likers.liker_id = '#{target_user}'") + query = query.where("claimed_recordings.is_public = TRUE OR claimed_recordings.user_id = '#{target_user}'") + + if query.length == 0 + [query, nil] + elsif query.length < limit + [query, nil] + else + [query, start + limit] + end + end + private def generate_share_token diff --git a/ruby/lib/jam_ruby/models/recording.rb b/ruby/lib/jam_ruby/models/recording.rb index 8fc666e0f..8102edb38 100644 --- a/ruby/lib/jam_ruby/models/recording.rb +++ b/ruby/lib/jam_ruby/models/recording.rb @@ -29,7 +29,6 @@ module JamRuby before_save :sanitize_active_admin before_create :add_to_feed - def add_to_feed feed = Feed.new feed.recording = self @@ -311,26 +310,6 @@ module JamRuby save end -=begin -# This is no longer remotely right. - def self.search(query, options = { :limit => 10 }) - - # only issue search if at least 2 characters are specified - if query.nil? || query.length < 2 - return [] - end - - # create 'anded' statement - query = Search.create_tsquery(query) - - if query.nil? || query.length == 0 - return [] - end - - return Recording.where("description_tsv @@ to_tsquery('jamenglish', ?)", query).limit(options[:limit]) - end -=end - private def self.validate_user_is_band_member(user, band) unless band.users.exists? user diff --git a/ruby/lib/jam_ruby/models/recording_liker.rb b/ruby/lib/jam_ruby/models/recording_liker.rb index a2a6d3aae..7c997d401 100644 --- a/ruby/lib/jam_ruby/models/recording_liker.rb +++ b/ruby/lib/jam_ruby/models/recording_liker.rb @@ -6,6 +6,7 @@ module JamRuby self.primary_key = 'id' belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id", :counter_cache => :like_count + belongs_to :claimed_recording, :class_name => "JamRuby::ClaimedRecording", :foreign_key => "claimed_recording_id" belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "liker_id" end diff --git a/ruby/lib/jam_ruby/models/recording_play.rb b/ruby/lib/jam_ruby/models/recording_play.rb index 5275c8ca5..56bd2d298 100644 --- a/ruby/lib/jam_ruby/models/recording_play.rb +++ b/ruby/lib/jam_ruby/models/recording_play.rb @@ -6,6 +6,7 @@ module JamRuby self.primary_key = 'id' belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id", :counter_cache => :play_count + belongs_to :claimed_recording, :class_name => "JamRuby::ClaimedRecording", :foreign_key => "claimed_recording_id" belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "player_id" end diff --git a/ruby/spec/jam_ruby/models/claimed_recording_spec.rb b/ruby/spec/jam_ruby/models/claimed_recording_spec.rb index 836b69ad9..f28e7a7e1 100644 --- a/ruby/spec/jam_ruby/models/claimed_recording_spec.rb +++ b/ruby/spec/jam_ruby/models/claimed_recording_spec.rb @@ -125,4 +125,91 @@ describe ClaimedRecording do instance.remove_non_alpha_num("JDnfHsimMQ").should == 'JDnfHsimMQ' end end + + describe "favorite_index" do + + let(:other_user) { FactoryGirl.create(:user) } + + it "returns nothing" do + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id) + favorites.length.should == 0 + start.should be_nil + end + + it "angry when no user specified" do + expect { ClaimedRecording.index_favorites(@user, user:other_user ) }.to raise_error "unable to view another user's favorites" + end + + it "user must be specified" do + expect { ClaimedRecording.index_favorites(@user) }.to raise_error "user must be specified" + end + + it "finds favorite claimed_recording if true, not if false" do + claimed_recording1 = FactoryGirl.create(:claimed_recording, user: @user) + + like = FactoryGirl.create(:recording_like, user: @user, claimed_recording: claimed_recording1, recording: claimed_recording1.recording, favorite: true) + + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id) + favorites.length.should == 1 + start.should be_nil + + like.favorite = false + like.save! + + # remove from favorites + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id) + favorites.length.should == 0 + start.should be_nil + end + + it "finds others public claimed recordings" do + claimed_recording1 = FactoryGirl.create(:claimed_recording, user: other_user) + + like = FactoryGirl.create(:recording_like, user: @user, claimed_recording: claimed_recording1, recording: claimed_recording1.recording, favorite: true) + + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id) + favorites.length.should == 1 + start.should be_nil + end + + it "can find others private claimed recordings" do + claimed_recording1 = FactoryGirl.create(:claimed_recording, user: other_user) + + like = FactoryGirl.create(:recording_like, user: @user, claimed_recording: claimed_recording1, recording: claimed_recording1.recording, favorite: false) + + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id) + favorites.length.should == 0 + start.should be_nil + end + + it "can find own private claimed recordings" do + claimed_recording1 = FactoryGirl.create(:claimed_recording, user: @user) + + like = FactoryGirl.create(:recording_like, user: @user, claimed_recording: claimed_recording1, recording: claimed_recording1.recording, favorite: true) + + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id) + favorites.length.should == 1 + start.should be_nil + end + + it "pagination" do + claimed_recording1 = FactoryGirl.create(:claimed_recording, user: @user) + claimed_recording2 = FactoryGirl.create(:claimed_recording, user: @user) + + like1 = FactoryGirl.create(:recording_like, user: @user, claimed_recording: claimed_recording1, recording: claimed_recording1.recording, favorite: true) + like2 = FactoryGirl.create(:recording_like, user: @user, claimed_recording: claimed_recording2, recording: claimed_recording2.recording, favorite: true) + + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id, limit:1) + favorites.length.should == 1 + start.should_not be_nil + + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id, limit:1, start: start) + favorites.length.should == 1 + start.should_not be_nil + + favorites, start = ClaimedRecording.index_favorites(@user, user: @user.id, limit:1, start: start) + favorites.length.should == 0 + start.should be_nil + end + end end \ No newline at end of file diff --git a/web/app/assets/javascripts/hoverRecording.js b/web/app/assets/javascripts/hoverRecording.js index e73fda527..385e39533 100644 --- a/web/app/assets/javascripts/hoverRecording.js +++ b/web/app/assets/javascripts/hoverRecording.js @@ -40,6 +40,7 @@ var recordingHtml = context.JK.fillTemplate(template, { recordingId: recording.id, + claimedRecordingId: claimedRecording.id name: claimedRecording.name, genre: claimedRecording.genre_id.toUpperCase(), created_at: context.JK.formatDateTime(recording.created_at), diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 5090066db..22f446469 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -83,21 +83,21 @@ }); } - function addRecordingLike(recordingId, userId) { + function addRecordingLike(recordingId, claimedRecordingId, userId) { return $.ajax({ url: '/api/recordings/' + recordingId + "/likes", type: "POST", - data : JSON.stringify({"user_id": userId}), + data : JSON.stringify({user_id: userId, claimed_recording: claimedRecordingId}), dataType : 'json', contentType: 'application/json' }); } - function addRecordingPlay(recordingId, userId) { + function addRecordingPlay(recordingId, claimedRecordingId, userId) { return $.ajax({ url: '/api/recordings/' + recordingId + "/plays", type: "POST", - data : JSON.stringify({"user_id": userId}), + data : JSON.stringify({user_id: userId, claimed_recording: claimedRecordingId}), dataType : 'json', contentType: 'application/json' }); diff --git a/web/app/assets/javascripts/web/recordings.js b/web/app/assets/javascripts/web/recordings.js index 4644d5beb..cea7ffcfd 100644 --- a/web/app/assets/javascripts/web/recordings.js +++ b/web/app/assets/javascripts/web/recordings.js @@ -8,7 +8,7 @@ var $scope = $(".landing-details"); function like() { - rest.addRecordingLike(recordingId, JK.currentUserId) + rest.addRecordingLike(recordingId, claimedRecordingId, JK.currentUserId) .done(function(response) { $("#spnLikeCount").html(parseInt($("#spnLikeCount").text()) + 1); $("#btnLike", $scope).unbind("click"); @@ -16,7 +16,7 @@ } function play() { - rest.addRecordingPlay(recordingId, JK.currentUserId) + rest.addRecordingPlay(recordingId, claimedRecordingId, JK.currentUserId) .done(function(response) { $("#spnPlayCount", $scope).html(parseInt($("#spnPlayCount").text()) + 1); }); diff --git a/web/app/controllers/api_favorites_controller.rb b/web/app/controllers/api_favorites_controller.rb new file mode 100644 index 000000000..5a9845ba8 --- /dev/null +++ b/web/app/controllers/api_favorites_controller.rb @@ -0,0 +1,17 @@ +class ApiFavoritesController < ApiController + + respond_to :json + + before_filter :api_signed_in_user + + def index + @claimed_recordings, @next = ClaimedRecording.index_favorites(current_user, + start: params[:since], + limit: params[:limit], + sort: params[:sort], + type: params[:type], + user: params[:user]) + + render "api_favorites/index", :layout => nil + end +end \ No newline at end of file diff --git a/web/app/controllers/api_recordings_controller.rb b/web/app/controllers/api_recordings_controller.rb index 1947b7baa..12099ab48 100644 --- a/web/app/controllers/api_recordings_controller.rb +++ b/web/app/controllers/api_recordings_controller.rb @@ -121,6 +121,8 @@ class ApiRecordingsController < ApiController liker = RecordingLiker.new liker.recording_id = params[:id] liker.liker_id = params[:user_id] + liker.claimed_recording_id = params[:claimed_recording_id] + liker.favorite = true liker.ip_address = request.remote_ip liker.save @@ -142,6 +144,7 @@ class ApiRecordingsController < ApiController play = RecordingPlay.new play.recording_id = params[:id] play.player_id = params[:user_id] + play.claimed_recording_id = params[:claimed_recording_id] play.ip_address = request.remote_ip play.save diff --git a/web/app/views/api_favorites/index.rabl b/web/app/views/api_favorites/index.rabl new file mode 100644 index 000000000..643b339bc --- /dev/null +++ b/web/app/views/api_favorites/index.rabl @@ -0,0 +1,7 @@ +node :next do |page| + @next +end + +node :entries do |page| + partial "api_claimed_recordings/show", object: @claimed_recordings +end \ No newline at end of file diff --git a/web/app/views/clients/_hoverRecording.html.erb b/web/app/views/clients/_hoverRecording.html.erb index 19272243b..50d75445e 100644 --- a/web/app/views/clients/_hoverRecording.html.erb +++ b/web/app/views/clients/_hoverRecording.html.erb @@ -38,7 +38,7 @@ {musicians}
-
LIKE
+
LIKE
SHARE
diff --git a/web/config/routes.rb b/web/config/routes.rb index dae5bba9f..472e40143 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -345,6 +345,9 @@ SampleApp::Application.routes.draw do # feed match '/feeds' => 'api_feeds#index', :via => :get + + # favorites + match '/favorites' => 'api_favorites#index', :via => :get end end diff --git a/web/spec/controllers/api_favorites_controller_spec.rb b/web/spec/controllers/api_favorites_controller_spec.rb new file mode 100644 index 000000000..ff634a23a --- /dev/null +++ b/web/spec/controllers/api_favorites_controller_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe ApiFavoritesController do + render_views + + let(:user) { FactoryGirl.create(:user) } + let(:user2) { FactoryGirl.create(:user) } + let(:band) { FactoryGirl.create(:band) } + let(:music_session) {FactoryGirl.create(:music_session, creator: user) } + let(:claimed_recording) {FactoryGirl.create(:claimed_recording) } + + before(:each) do + ClaimedRecording.delete_all + controller.current_user = nil + end + + + it "insists on login" do + get :index + response.status.should == 403 + end + + it "requires user param" do + controller.current_user = user + expect { get :index }.to raise_error "user must be specified" + end + + it "can return nothing" do + controller.current_user = user + get :index, { user: user} + + json = JSON.parse(response.body, :symbolize_names => true) + json[:entries].length.should == 0 + json[:since].should be_nil + end + + it "returns one thing" do + claimed_recording.touch + like = FactoryGirl.create(:recording_like, user: user, claimed_recording: claimed_recording, recording: claimed_recording.recording, favorite: true) + + controller.current_user = user + get :index, { user: user} + + json = JSON.parse(response.body, :symbolize_names => true) + json[:entries].length.should == 1 + json[:since].should be_nil + end +end diff --git a/web/spec/factories.rb b/web/spec/factories.rb index 1d5716708..d805af4a7 100644 --- a/web/spec/factories.rb +++ b/web/spec/factories.rb @@ -352,4 +352,20 @@ FactoryGirl.define do sequence(:token) { |n| "token-#{n}"} token_expires_at Time.now end + + factory :recording_play, :class => JamRuby::RecordingPlay do + + end + + factory :music_session_play, :class => JamRuby::MusicSessionPlay do + + end + + factory :recording_like, :class => JamRuby::RecordingLiker do + + end + + factory :music_session_like, :class => JamRuby::MusicSessionLiker do + + end end diff --git a/web/spec/spec_helper.rb b/web/spec/spec_helper.rb index 40d775465..bb614463c 100644 --- a/web/spec/spec_helper.rb +++ b/web/spec/spec_helper.rb @@ -19,19 +19,37 @@ db_config = YAML::load(File.open('config/database.yml'))["test"] # initialize ActiveRecord's db connection\ SpecDb::recreate_database(db_config) ActiveRecord::Base.establish_connection(YAML::load(File.open('config/database.yml'))["test"]) +#puts "0" require 'jam_ruby' # uncomment this to see active record logs # ActiveRecord::Base.logger = Logger.new(STDOUT) if defined?(ActiveRecord::Base) +#puts "1" include JamRuby +#puts "2" # put ActionMailer into test mode ActionMailer::Base.delivery_method = :test +#puts "3" RecordedTrack.observers.disable :all # only a few tests want this observer active +#puts "4" +# a way to kill tests if they aren't running. capybara is hanging intermittently, I think + +tests_started = false + +#Thread.new { +# puts "thread statring" +# sleep 30 +# puts "thread waking" +# unless tests_started + +# exit 20 +# end +#} Spork.prefork do # Loading more in this block will cause your tests to run faster. However, @@ -105,11 +123,10 @@ Spork.prefork do config.include Requests::FeatureHelpers, type: :feature config.before(:suite) do - + tests_started = true end config.before(:all) do - end config.before(:each) do