* VRFS-1160 - favorites REST API done

This commit is contained in:
Seth Call 2014-02-20 20:54:35 +00:00
parent 061c74f8c6
commit aab902e8cf
18 changed files with 268 additions and 38 deletions

View File

@ -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
music_session_history_public.sql
track_claimed_recording.sql

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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'
});

View File

@ -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);
});

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,7 @@
node :next do |page|
@next
end
node :entries do |page|
partial "api_claimed_recordings/show", object: @claimed_recordings
end

View File

@ -38,7 +38,7 @@
{musicians}
</table><br />
<div align="center">
<div class="left"><a id="btnLike" onclick="addRecordingLike('{recordingId}');" class="button-orange">LIKE</a></div>
<div class="left"><a id="btnLike" onclick="addRecordingLike('{recordingId}', '{claimedRecordingId}');" class="button-orange">LIKE</a></div>
<div style="display:none;" class="left"><a id="btnComment" class="button-orange">COMMENT</a></div>
<div class="left"><a id="btnShare" layout-link="share-dialog" class="button-orange">SHARE</a></div>
</div>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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