Merge update

This commit is contained in:
Steven Miers 2014-11-10 17:10:01 -06:00
commit 6c825db79f
66 changed files with 1276 additions and 283 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ HTML
.DS_Store
coverage
dump.rdb
working.png

View File

@ -228,3 +228,4 @@ user_syncs_fix_dup_tracks_2408.sql
jam_tracks.sql
shopping_carts.sql
recurly.sql
deletable_recordings.sql

View File

@ -0,0 +1,39 @@
-- this is to make sure we don't delete any recordings for 7 days
UPDATE recordings SET updated_at = NOW();
ALTER TABLE recordings ADD COLUMN deleted BOOLEAN DEFAULT FALSE NOT NULL;
DROP VIEW user_syncs;
CREATE VIEW user_syncs AS
SELECT DISTINCT b.id AS recorded_track_id,
CAST(NULL as BIGINT) AS mix_id,
CAST(NULL as BIGINT) as quick_mix_id,
b.id AS unified_id,
a.user_id AS user_id,
b.fully_uploaded,
recordings.created_at AS created_at,
recordings.id AS recording_id
FROM recorded_tracks a INNER JOIN recordings ON a.recording_id = recordings.id AND duration IS NOT NULL AND all_discarded = FALSE AND deleted = FALSE INNER JOIN recorded_tracks b ON a.recording_id = b.recording_id
UNION ALL
SELECT CAST(NULL as BIGINT) AS recorded_track_id,
mixes.id AS mix_id,
CAST(NULL as BIGINT) AS quick_mix_id,
mixes.id AS unified_id,
claimed_recordings.user_id AS user_id,
NULL as fully_uploaded,
recordings.created_at AS created_at,
recordings.id AS recording_id
FROM mixes INNER JOIN recordings ON mixes.recording_id = recordings.id INNER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id WHERE claimed_recordings.discarded = FALSE AND deleted = FALSE
UNION ALL
SELECT CAST(NULL as BIGINT) AS recorded_track_id,
CAST(NULL as BIGINT) AS mix_id,
quick_mixes.id AS quick_mix_id,
quick_mixes.id AS unified_id,
quick_mixes.user_id,
quick_mixes.fully_uploaded,
recordings.created_at AS created_at,
recordings.id AS recording_id
FROM quick_mixes INNER JOIN recordings ON quick_mixes.recording_id = recordings.id AND duration IS NOT NULL AND all_discarded = FALSE AND deleted = FALSE;

View File

@ -54,6 +54,7 @@ require "jam_ruby/resque/scheduled/music_session_scheduler"
require "jam_ruby/resque/scheduled/active_music_session_cleaner"
require "jam_ruby/resque/scheduled/score_history_sweeper"
require "jam_ruby/resque/scheduled/scheduled_music_session_cleaner"
require "jam_ruby/resque/scheduled/recordings_cleaner"
require "jam_ruby/resque/google_analytics_event"
require "jam_ruby/resque/batch_email_job"
require "jam_ruby/mq_router"

View File

@ -11,9 +11,6 @@ module JamRuby
# https://github.com/assistly/multipass-examples/blob/master/ruby.rb
class DeskMultipass
API_KEY = "453ddfc0bab00130a9c13bc9a68cf24c"
SITE_KEY = "jamkazam"
def initialize(user)
@user = user
generate_token_and_signature
@ -29,7 +26,7 @@ module JamRuby
private
def generate_token_and_signature
key = Digest::SHA1.digest(API_KEY + SITE_KEY)[0...16]
key = Digest::SHA1.digest(APP_CONFIG.desk_multipass_key + APP_CONFIG.desk_multipass_site)[0...16]
# Generate a random 16 byte IV
iv = OpenSSL::Random.random_bytes(16)
@ -48,7 +45,7 @@ module JamRuby
prepended = iv + encrypted
token = Base64.encode64(prepended)
signature = Base64.encode64(OpenSSL::HMAC.digest('sha1', API_KEY, token))
signature = Base64.encode64(OpenSSL::HMAC.digest('sha1', APP_CONFIG.desk_multipass_key, token))
@token = CGI.escape(token)
@signature = CGI.escape(signature)

View File

@ -35,7 +35,7 @@ module JamRuby
query = Feed.joins("LEFT OUTER JOIN recordings ON recordings.id = feeds.recording_id")
.joins("LEFT OUTER JOIN music_sessions ON music_sessions.id = feeds.music_session_id")
.limit(limit)
.where('recordings is NULL OR recordings.all_discarded = false') # remove any 'all_discarded recordings from the search results'
.where('recordings is NULL OR (recordings.all_discarded = false AND recordings.deleted = false)') # remove any 'all_discarded recordings from the search results' or 'deleted'
# handle sort
if sort == 'date'

View File

@ -198,13 +198,15 @@ module JamRuby
self.last_downloaded_at = Time.now
end
private
def delete_s3_files
s3_manager.delete(filename(type='ogg')) if self[:ogg_url]
s3_manager.delete(filename(type='mp3')) if self[:mp3_url]
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'))
end
private
def self.construct_filename(created_at, recording_id, id, type='ogg')
raise "unknown ID" unless id

View File

@ -219,11 +219,12 @@ module JamRuby
self.last_downloaded_at = Time.now
end
def delete_s3_files
s3_manager.delete(self[:url]) if self[:url] && s3_manager.exists?(self[:url])
end
private
def delete_s3_files
s3_manager.delete(self[:url]) if self[:url]
end
def self.construct_filename(created_at, recording_id, client_track_id)
raise "unknown ID" unless client_track_id

View File

@ -1,12 +1,8 @@
module JamRuby
class Recording < ActiveRecord::Base
self.primary_key = 'id'
@@log = Logging.logger[Recording]
attr_accessible :owner, :owner_id, :band, :band_id, :recorded_tracks_attributes, :mixes_attributes, :claimed_recordings_attributes, :name, :description, :genre, :is_public, :duration, as: :admin
has_many :users, :through => :recorded_tracks, :class_name => "JamRuby::User"
@ -234,8 +230,6 @@ module JamRuby
self
end
# 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
@ -264,6 +258,8 @@ module JamRuby
def keep(user)
recorded_tracks_for_user(user).update_all(:discard => false)
Recording.where(:id => id).update_all(:updated_at => Time.now) # updated updated_at for benefit of RecordingsCleaner
User.where(:id => user.id).update_all(:first_recording_at => Time.now ) unless user.first_recording_at
end
@ -272,6 +268,8 @@ module JamRuby
def discard(user)
recorded_tracks_for_user(user).update_all(:discard => true)
Recording.where(:id => id).update_all(:updated_at => Time.now) # updated updated_at for benefit of RecordingsCleaner
# check if all recorded_tracks for this recording are discarded
if recorded_tracks.where('discard = false or discard is NULL').length == 0
self.all_discarded = true # the feed won't pick this up; also background cleanup will find these and whack them later
@ -308,6 +306,8 @@ module JamRuby
.order('recorded_tracks.id')
.where('recorded_tracks.fully_uploaded = TRUE')
.where('recorded_tracks.id > ?', since)
.where('all_discarded = false')
.where('deleted = false')
.where('claimed_recordings.user_id = ? AND claimed_recordings.discarded = FALSE', user).limit(limit).each do |recorded_track|
downloads.push(
{
@ -328,6 +328,8 @@ module JamRuby
.order('mixes.id')
.where('mixes.completed_at IS NOT NULL')
.where('mixes.id > ?', since)
.where('all_discarded = false')
.where('deleted = false')
.where('claimed_recordings.user_id = ? AND claimed_recordings.discarded = FALSE', user)
.limit(limit).each do |mix|
downloads.push(
@ -462,6 +464,7 @@ module JamRuby
.where("upload_failures <= #{APP_CONFIG.max_track_upload_failures}") \
.where("duration IS NOT NULL") \
.where('all_discarded = false') \
.where('deleted = false') \
.order('recorded_items_all.id') \
.limit(limit)
@ -537,10 +540,71 @@ module JamRuby
end
# returns a ClaimedRecording that the user did not discard
def claim_for_user(user)
def claim_for_user(user, ignore_discarded = false)
return nil unless user
claim = claimed_recordings.find{|claimed_recording| claimed_recording.user == user }
claim unless claim && claim.discarded
if ignore_discarded
claim
else
claim unless claim && claim.discarded
end
end
def self.when_will_be_discarded?
recorded_track_votes = recorded_tracks.map(&:discard)
discarded = 0
recorded_track_votes.each do |discard_vote|
if discard_vote == nil || discard_vote == true
discarded = discarded + 1
end
end
if recorded_track_votes.length == discarded
# all tracks are discarded, figure out due time for deletion
# 3 days in seconds - amount of seconds since last updated
((APP_CONFIG.recordings_stale_time * 3600 * 24) - (Time.now - updated_at).to_i).seconds.from_now
else
return nil
end
end
# finds all discarded recordings that are sufficiently stale (i.e., abandoned by all those involved, and hasn't been mucked with in a while)
def self.discarded_and_stale
# we count up all tracks for the Recording, and count up all discarded/not-voted-on tracks
# if they are equal, and if the recording is stale, let's return it.
Recording
.joins("INNER JOIN recorded_tracks ON recordings.id = recorded_tracks.recording_id")
.joins(%Q{
LEFT OUTER JOIN
(SELECT id
FROM recorded_tracks WHERE discard IS NULL OR discard = TRUE) AS discard_info
ON recorded_tracks.id = discard_info.id
})
.group("recordings.id")
.having('COUNT(recorded_tracks.id) = COUNT(discard_info.id)')
.where("NOW() - recordings.updated_at > '#{APP_CONFIG.recordings_stale_time} day'::INTERVAL")
.limit(1000)
end
def mark_delete
mixes.each do |mix|
mix.delete_s3_files
end
quick_mixes.each do |quick_mix|
quick_mix.delete_s3_files
end
recorded_tracks.each do |recorded_track|
recorded_track.delete_s3_files
end
self.deleted = true
self.save(:validate => false)
end
private

View File

@ -313,7 +313,7 @@ module JamRuby
end
def session_count
self.music_sessions.size
MusicSession.where("user_id = ? AND started_at IS NOT NULL", self.id).size
end
# count up any session you are RSVP'ed to

View File

@ -21,7 +21,15 @@ module JamRuby
raise 'no user id specified' if user_id.blank?
query = UserSync.includes(recorded_track: [{recording: [:owner, {claimed_recordings: [:share_token]}, {recorded_tracks: [:user]}, {comments:[:user]}, :likes, :plays, :mixes]}, user: [], instrument:[]], mix: [], quick_mix:[]).where(user_id: user_id).paginate(:page => page, :per_page => limit).order('created_at DESC, unified_id')
query = UserSync
.includes(recorded_track: [{recording: [:owner, {claimed_recordings: [:share_token]}, {recorded_tracks: [:user]}, {comments:[:user]}, :likes, :plays, :mixes]}, user: [], instrument:[]], mix: [], quick_mix:[])
.joins("LEFT OUTER JOIN claimed_recordings ON claimed_recordings.user_id = user_syncs.user_id AND claimed_recordings.recording_id = user_syncs.recording_id")
.where(user_id: user_id)
.where(%Q{
((claimed_recordings IS NULL OR claimed_recordings.discarded = TRUE) AND fully_uploaded = FALSE) OR (claimed_recordings IS NOT NULL AND claimed_recordings.discarded = FALSE)
})
.paginate(:page => page, :per_page => limit)
.order('created_at DESC, unified_id')
# allow selection of single user_sync, by ID
@ -41,6 +49,31 @@ module JamRuby
{ query:query, next: offset + limit}
end
end
def self.deletables(params)
user_id = params[:user_id]
recording_ids = params[:recording_ids]
limit = 1000
recording_ids = recording_ids.uniq
raise "too many recording_ids" if recording_ids.length > limit
found_recording_ids =
UserSync
.select('user_syncs.recording_id')
.joins("LEFT OUTER JOIN claimed_recordings ON claimed_recordings.user_id = user_syncs.user_id")
.where(%Q{
((claimed_recordings IS NULL OR claimed_recordings.discarded = TRUE) AND fully_uploaded = FALSE) OR (claimed_recordings IS NOT NULL AND claimed_recordings.discarded = FALSE)
})
.where(user_id: user_id)
.paginate(:page => 1, :per_page => limit)
.group('user_syncs.recording_id').map(&:recording_id)
recording_ids - found_recording_ids
end
end
end

View File

@ -65,10 +65,9 @@ module JamRuby
cleanup_files
@@log.info("audiomixer job successful. mix_id #{quick_mix_id}")
@@log.info("quickmixer job successful. mix_id #{quick_mix_id}")
rescue Exception => e
puts "EEOUOU #{e}"
post_error(@quick_mix, e)
raise
end

View File

@ -0,0 +1,32 @@
require 'json'
require 'resque'
require 'resque-retry'
require 'net/http'
require 'digest/md5'
module JamRuby
# periodically scheduled to find recordings to cleanup
class RecordingsCleaner
extend Resque::Plugins::LonelyJob
@queue = :recordings_cleaner
@@log = Logging.logger[RecordingsCleaner]
def self.lock_timeout
# this should be enough time to make sure the job has finished, but not so long that the system isn't recovering from a abandoned job
1200
end
def self.perform
discarded_recordings = Recording.discarded_and_stale
discarded_recordings.each do |recording|
@@log.debug("deleting recording #{recording.id}")
recording.mark_delete
end
end
end
end

View File

@ -250,8 +250,6 @@ FactoryGirl.define do
end
factory :recorded_video, :class => JamRuby::RecordedVideo do
sequence(:client_id) { |n| "client_id-#{n}"}
sequence(:recording_id) { |n| "recording_id-#{n}"}
sequence(:client_video_source_id) { |n| "client_video_source_id-#{n}"}
fully_uploaded true
length 1
@ -283,14 +281,17 @@ FactoryGirl.define do
association :genre, factory: :genre
association :user, factory: :user
before(:create) { |claimed_recording|
claimed_recording.recording = FactoryGirl.create(:recording_with_track, owner: claimed_recording.user) unless claimed_recording.recording
before(:create) { |claimed_recording, evaluator|
claimed_recording.recording = FactoryGirl.create(:recording_with_track, owner: claimed_recording.user) unless evaluator.recording
}
end
factory :mix, :class => JamRuby::Mix do
ignore do
autowire true
end
started_at Time.now
completed_at Time.now
ogg_md5 'abc'
@ -301,10 +302,12 @@ FactoryGirl.define do
sequence(:mp3_url) { |n| "recordings/mp3/#{n}" }
completed true
before(:create) {|mix|
user = FactoryGirl.create(:user)
mix.recording = FactoryGirl.create(:recording_with_track, owner: user)
mix.recording.claimed_recordings << FactoryGirl.create(:claimed_recording, user: user, recording: mix.recording)
before(:create) {|mix, evaluator|
if evaluator.autowire
user = FactoryGirl.create(:user)
mix.recording = FactoryGirl.create(:recording_with_track, owner: user)
mix.recording.claimed_recordings << FactoryGirl.create(:claimed_recording, user: user, recording: mix.recording)
end
}
end
@ -330,6 +333,19 @@ FactoryGirl.define do
mix.recording.claimed_recordings << FactoryGirl.create(:claimed_recording, user: user, recording: mix.recording)
end
}
factory :quick_mix_completed do
started_at 1.minute.ago
completed_at Time.now
ogg_md5 'a'
ogg_length 1
ogg_url 'recordings/ogg'
mp3_md5 'a'
mp3_length 1
mp3_url 'recordings/mp3'
completed true
end
end
factory :invited_user, :class => JamRuby::InvitedUser do
@ -526,6 +542,13 @@ FactoryGirl.define do
token_expires_at Time.now
end
factory :recording_comment, :class => JamRuby::RecordingComment do
sequence(:comment) { |n| "comment-#{n}" }
association :recording, factory: :recording
association :user, factory: :recording
end
factory :playable_play, :class => JamRuby::PlayablePlay do
end

View File

@ -464,5 +464,19 @@ describe Feed do
end
end
describe "deleted recording" do
it "should not show" do
claimed_recording = FactoryGirl.create(:claimed_recording)
MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording
MusicSession.delete_all # the factory makes a music_session while making the recording/claimed_recording
recording = claimed_recording.recording
recording.mark_delete
recording.reload
recording.deleted.should == true
feeds, next_page = Feed.index(user1)
feeds.length.should == 0
end
end
end

View File

@ -430,6 +430,19 @@ describe Recording do
Recording.list_uploads(@user, 10, uploads["next"])["uploads"].length.should == 0
end
it "should not consider deleted recordings" do
stub_const("APP_CONFIG", app_config)
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
@genre = FactoryGirl.create(:genre)
@recording.claim(@user, "Recording", "Recording Description", @genre, true)
@recording.mark_delete
uploads = Recording.list_uploads(@user)
uploads["uploads"].length.should == 0
end
it "should return a download only if claimed" do
@recording = Recording.start(@music_session, @user)
@recording.stop
@ -444,6 +457,21 @@ describe Recording do
downloads["downloads"].length.should == 1
end
it "should not return a download if recording is deleted" do
@recording = Recording.start(@music_session, @user)
@recording.stop
@recording.reload
@genre = FactoryGirl.create(:genre)
@recording.claim(@user, "Recording", "Recording Description", @genre, true)
downloads = Recording.list_downloads(@user)
downloads["downloads"].length.should == 0
@recorded_track = RecordedTrack.where(:recording_id => @recording.id)[0]
@recorded_track.update_attribute(:fully_uploaded, true)
@recording.mark_delete
downloads = Recording.list_downloads(@user)
downloads["downloads"].length.should == 0
end
it "should mark first_recording_at" do
@recording = Recording.start(@music_session, @user)
@recording.stop
@ -638,6 +666,388 @@ describe Recording do
uploads["uploads"].should have(0).items
end
describe "discarded_and_stale" do
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
end
describe "with one recording" do
before(:each) do
track1.discard.should be_nil
end
describe "that has no votes" do
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
# and we should find it now...
stale = Recording.discarded_and_stale
stale.first.should eq(recording1)
end
end
describe "that has discard vote" do
before(:each) do
track1.discard = true
track1.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
# and we should find it now...
stale = Recording.discarded_and_stale
stale.first.should eq(recording1)
end
end
describe "that has keep vote" do
before(:each) do
track1.discard = false
track1.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "still not found it has an old updated_at time, because it was kept" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
# and still not find it
stale = Recording.discarded_and_stale
stale.length.should == 0
end
end
describe "that has two tracks, no votes" do
let(:track2) { FactoryGirl.create(:recorded_track, recording: recording1, user: recording1.owner) }
before(:each) do
track1.discard = nil
track1.save!
recording1.recorded_tracks << track2
recording1.save!
track2.discard = nil
track2.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
# and we should find it now...
stale = Recording.discarded_and_stale
stale.first.should eq(recording1)
end
end
end
describe "that has two tracks, two discard" do
let(:track2) { FactoryGirl.create(:recorded_track, recording: recording1, user: recording1.owner) }
before(:each) do
track1.discard = true
track1.save!
recording1.recorded_tracks << track2
recording1.save!
track2.discard = true
track2.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
# and we should find it now...
stale = Recording.discarded_and_stale
stale.first.should eq(recording1)
end
end
describe "that has two tracks, one discard, one keep" do
let(:track2) { FactoryGirl.create(:recorded_track, recording: recording1, user: recording1.owner) }
before(:each) do
track1.discard = true
track1.save!
recording1.recorded_tracks << track2
recording1.save!
track2.discard = false
track2.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 0
end
end
describe "that has two tracks, two keeps" do
let(:track2) { FactoryGirl.create(:recorded_track, recording: recording1, user: recording1.owner) }
before(:each) do
track1.discard = false
track1.save!
recording1.recorded_tracks << track2
recording1.save!
track2.discard = false
track2.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 0
end
end
describe "two recordings" do
let(:recording2) {FactoryGirl.create(:recording_with_track)}
let(:track2) {recording2.recorded_tracks[0]}
describe "both discard" do
before(:each) do
track1.discard = true
track1.save!
track2.discard = true
track2.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 1
stale.first.should eq(recording1)
Recording.where(:id => recording2.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 2
end
end
describe "both keep" do
before(:each) do
track1.discard = false
track1.save!
track2.discard = false
track2.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 0
Recording.where(:id => recording2.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 0
end
end
describe "one keep, one discard" do
before(:each) do
track1.discard = false
track1.save!
track2.discard = true
track2.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 0
Recording.where(:id => recording2.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 1
stale.first.should eq(recording2)
end
end
describe "two keeps, two discards" do
let(:track1_2) { FactoryGirl.create(:recorded_track, recording: recording1, user: recording1.owner) }
let(:track2_2) { FactoryGirl.create(:recorded_track, recording: recording2, user: recording1.owner) }
before(:each) do
track1.discard = false
track1.save!
recording1.recorded_tracks << track1_2
recording1.save!
track1_2.discard = false
track1_2.save!
track2.discard = true
track2.save!
recording2.recorded_tracks << track2_2
recording2.save!
track2_2.discard = true
track2_2.save!
end
it "not found if it has recent updated_at time" do
stale = Recording.discarded_and_stale
stale.length.should == 0
end
it "found if it has an old updated_at time" do
# now age the recording
Recording.where(:id => recording1.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 0
Recording.where(:id => recording2.id).update_all(:updated_at => (APP_CONFIG.recordings_stale_time + 1).days.ago)
stale = Recording.discarded_and_stale
stale.length.should == 1
stale.first.should eq(recording2)
end
end
end
end
describe "delete" do
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(:recording_comment, recording: recording, user: recording.owner)
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
recording.claimed_recordings.length.should > 0
recording.mixes.length.should > 0
recording.quick_mixes.length.should > 0
recording.recorded_tracks.length.should > 0
recording.comments.length.should > 0
recording.likes.length.should > 0
recording.plays.length.should > 0
recording.recorded_videos.length.should > 0
recording.feed.should_not be_nil
claimed_recording = recording.claimed_recordings.first
quick_mix = recording.quick_mixes.first
track = recording.recorded_tracks.first
comment = recording.comments.first
like = recording.likes.first
play = recording.plays.first
feed = recording.feed
video = recording.recorded_videos.first
recording.mark_delete
ClaimedRecording.find_by_id(claimed_recording.id).should_not be_nil
Mix.find_by_id(mix.id).should_not be_nil
QuickMix.find_by_id(quick_mix.id).should_not be_nil
RecordedTrack.find_by_id(track.id).should_not be_nil
RecordingComment.find_by_id(comment.id).should_not be_nil
PlayablePlay.find_by_id(play.id).should_not be_nil
RecordingLiker.find_by_id(like.id).should_not be_nil
Feed.find_by_id(feed.id).should_not be_nil
RecordedVideo.find_by_id(video.id).should_not be_nil
end
end
end

View File

@ -20,19 +20,41 @@ describe UserSync do
data[:next].should be_nil
end
it "one mix" do
it "one mix and quick mix" do
mix = FactoryGirl.create(:mix)
mix.recording.duration = 1
mix.recording.save!
quick_mix = FactoryGirl.create(:quick_mix_completed, recording:mix.recording, user: mix.recording.recorded_tracks[0].user, autowire:false)
data = UserSync.index({user_id: mix.recording.recorded_tracks[0].user.id})
data[:next].should be_nil
user_syncs = data[:query]
user_syncs.length.should == 2
user_syncs.length.should == 3
user_syncs[0].recorded_track.should == mix.recording.recorded_tracks[0]
user_syncs[0].mix.should be_nil
user_syncs[0].quick_mix.should be_nil
user_syncs[1].mix.should == mix
user_syncs[1].recorded_track.should be_nil
user_syncs[1].quick_mix.should be_nil
user_syncs[2].mix.should be_nil
user_syncs[2].recorded_track.should be_nil
user_syncs[2].quick_mix.should eq(quick_mix)
end
# https://jamkazam.atlassian.net/browse/VRFS-2450
it "no longer returned after fully uploaded and unclaimed" do
mix = FactoryGirl.create(:mix)
mix.recording.duration = 1
mix.recording.save!
quick_mix = FactoryGirl.create(:quick_mix_completed, recording:mix.recording, user: mix.recording.recorded_tracks[0].user, autowire:false, fully_uploaded: true)
mix.recording.recorded_tracks[0].fully_uploaded = true
mix.recording.recorded_tracks[0].save!
mix.recording.claimed_recordings[0].discarded = true
mix.recording.claimed_recordings[0].save!
data = UserSync.index({user_id: mix.recording.recorded_tracks[0].user.id})
user_syncs = data[:query]
user_syncs.length.should == 0
end
it "two mixes, one not belonging to querier" do
@ -65,8 +87,8 @@ describe UserSync do
describe "one recording with two users" do
let!(:recording1) {
recording = FactoryGirl.create(:recording, owner: user1, band: nil, duration:1)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner, fully_uploaded:false)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2, fully_uploaded:false)
recording.save!
recording.reload
recording
@ -171,10 +193,10 @@ describe UserSync do
describe "one recording with multi-track users" do
let!(:recording1) {
recording = FactoryGirl.create(:recording, owner: user1, band: nil, duration:1)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner, fully_uploaded:false)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner, fully_uploaded:false)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2, fully_uploaded:false)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2, fully_uploaded:false)
recording.save!
recording.reload
recording
@ -222,6 +244,7 @@ describe UserSync do
recording = FactoryGirl.create(:recording, owner: user1, band: nil, duration:1)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner)
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: user2)
claimed_recording = FactoryGirl.create(:claimed_recording, user: recording.owner, recording: recording, discarded:false)
recording.save!
recording.reload
recording
@ -267,8 +290,204 @@ describe UserSync do
user_syncs = data[:query]
user_syncs.length.should == 0
data[:query].total_entries.should == 2
end
end
it "does not return deleted recordings" do
mix = FactoryGirl.create(:mix)
mix.recording.duration = 1
mix.recording.save!
quick_mix = FactoryGirl.create(:quick_mix_completed, recording:mix.recording, user: mix.recording.recorded_tracks[0].user, autowire:false)
mix.recording.mark_delete
data = UserSync.index({user_id: mix.recording.recorded_tracks[0].user.id})
data[:next].should be_nil
user_syncs = data[:query]
user_syncs.length.should == 0
end
describe "deletable" do
describe "one mix and one quick mix" do
let!(:mix) { m = FactoryGirl.create(:mix); m.recording.duration = 1; m.recording.save!; m}
let!(:quick_mix) { FactoryGirl.create(:quick_mix_completed, recording:mix.recording, user: mix.recording.recorded_tracks[0].user, autowire:false) }
it "unknown id" do
recording_ids = ['1']
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq(recording_ids)
end
it "unknown ids" do
recording_ids = ['1', '2', '3']
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq(recording_ids)
end
it "valid recording id" do
recording_ids = [mix.recording.id]
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq([])
end
it "valid recording id" do
recording_ids = [mix.recording.id]
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq([])
end
it "valid recording_id mixed with unknown ids" do
recording_ids = [mix.recording.id, '1']
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq(['1'])
end
end
describe "two recordings" do
let!(:mix) { m = FactoryGirl.create(:mix); m.recording.duration = 1; m.recording.save!; m}
let!(:quick_mix) { FactoryGirl.create(:quick_mix_completed, recording:mix.recording, user: mix.recording.recorded_tracks[0].user, autowire:false) }
let!(:mix2) { m = FactoryGirl.create(:mix); m.recording.duration = 1; m.recording.save!; m}
let!(:quick_mix2) { FactoryGirl.create(:quick_mix_completed, recording:mix2.recording, user: mix2.recording.recorded_tracks[0].user, autowire:false) }
before(:each) do
# fix up the user associated with the second mix/recording to be same as 1st
mix2.recording.owner = mix.recording.owner
mix2.recording.save!
mix2.recording.recorded_tracks[0].user = mix.recording.owner
mix2.recording.recorded_tracks[0].save!
end
it "unknown id" do
recording_ids = ['1']
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq(recording_ids)
end
it "unknown ids" do
recording_ids = ['1', '2', '3']
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq(recording_ids)
end
it "valid recording id" do
recording_ids = [mix.recording.id, mix2.recording.id]
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq([])
end
it "valid recording id" do
recording_ids = [mix.recording.id]
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq([])
end
it "valid recording_id mixed with unknown ids" do
recording_ids = [mix.recording.id, '1']
result = UserSync.deletables(user_id: mix.recording.recorded_tracks[0].user.id, recording_ids: recording_ids)
result.should eq(['1'])
end
end
it "resolved recordings" do
# start with a recording with a fully uploaded recorded_track, and no claim
recording = FactoryGirl.create(:recording_with_track, owner: user1)
recording.duration = 1
recording.save!
recording_ids = [recording.id]
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq(recording_ids)
# set the recorded_track to not fully uploaded, which should make it not deletable
recording.recorded_tracks[0].fully_uploaded = false
recording.recorded_tracks[0].save!
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq([])
# mark recording as deleted, which should make it deletable
recording.deleted = true
recording.save!
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq(recording_ids)
# mark recording as fully discarded, which should make it deletable
recording.all_discarded = true
recording.deleted = false
recording.save!
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq(recording_ids)
# claim the recording, and make the track not fully uploaded
recording.recorded_tracks[0].fully_uploaded = false
recording.all_discarded = false
claim = FactoryGirl.create(:claimed_recording, user: user1, recording: recording)
recording.save!
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq([])
# create a mix while still claiming the recording
mix = FactoryGirl.create(:mix, autowire:false, recording:recording)
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq([])
# now take away the claim, and make sure the track is fully uploaded
claim.discarded = true
claim.save!
# without a claimed recording, make the track fully uploaded, so as to not trigger 'need to upload' logic
recording.recorded_tracks[0].fully_uploaded = true
recording.recorded_tracks[0].save!
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq(recording_ids)
# if we make a quick mix, but still have no claim, we still should still need to delete the recording
quick_mix = FactoryGirl.create(:quick_mix, autowire:false, user: user1, recording: recording, fully_uploaded: true)
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq(recording_ids)
# make the quick_mix be not fully_uploaded, which should make it not be marked for deleting because we need to upload it
quick_mix.fully_uploaded = false
quick_mix.save!
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq([])
quick_mix.fully_uploaded = true
quick_mix.save!
claim.discarded = false
claim.save!
result = UserSync.deletables(user_id: user1.id, recording_ids: recording_ids)
result.should eq([])
end
end
end

View File

@ -138,6 +138,10 @@ def app_config
2 # don't put to 1; it'll break tests
end
def recordings_stale_time
7
end
private
def audiomixer_workspace_path

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -92,7 +92,9 @@
.done(function(openSlots) {
if (openSlots) {
if (openSlots.length === 0) {
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName);
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName, function() {
approve(rsvpId, params);
});
}
else {
var arrInstrumentIds = instrumentIds.split('|');
@ -122,7 +124,9 @@
}
}
else {
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName);
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName, function() {
approve(rsvpId, params);
});
}
});
}

View File

@ -23,6 +23,7 @@
var nextPage = 1;
var $includeType = null;
var didLoadAllFeeds = false, isLoading = false;
var $templateRecordingDiscardedSoon = null;
function defaultQuery() {
var query = { limit: feedBatchSize };
@ -441,6 +442,15 @@
var $feedItem = $(context._.template($('#template-feed-recording').html(), options, {variable: 'data'}));
var $controls = $feedItem.find('.recording-controls');
var $titleText = $feedItem.find('.title .title-text');
// if this item will be discarded, tack on a * to the RECORDING NAME
var discardTime = feed['when_will_be_discarded?'];
if(discardTime) {
context.JK.helpBubble($titleText, 'recording-discarded-soon', {discardTime: discardTime}, {});
$titleText.text($titleText.text() + '*');
}
$controls.data('mix-state', feed.mix_info) // for recordingUtils helper methods
$controls.data('server-info', feed.mix) // for recordingUtils helper methods
$controls.data('view-context', 'feed')
@ -589,6 +599,7 @@
$includeDate.val(defaults.time_range)
$includeType.val(defaults.type)
$templateRecordingDiscardedSoon = $('#template-help-recording-discarded-soon');
events();
}

View File

@ -204,7 +204,7 @@
// @FIXME -- this will need to be tweaked when we allow unfollowing
$('div[data-band-id='+newFollowing.band_id+'] .search-m-follow').removeClass('button-orange').addClass('button-grey');
},
error: app.ajaxError
error: app.ajaxError(arguments)
});
}

View File

@ -76,7 +76,7 @@
if (response.internet_score && response.internet_score.length > 0) {
if (response.internet_score[0].score && !isNaN(response.internet_score[0].score)) {
var internetScore = parseInt(response.internet_score[0].score);
fullScore = (response.internet_score + calculateAudioLatency(response.my_audio_latency) + calculateAudioLatency(response.last_jam_audio_latency)) / 2;
fullScore = (internetScore + calculateAudioLatency(response.my_audio_latency) + calculateAudioLatency(response.last_jam_audio_latency)) / 2;
}
}

View File

@ -58,7 +58,7 @@
instrumentHtml = '<td><div class="nowrap">';
$.each(val.instrument_ids, function(index, val) {
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(val) + '" width="24" height="24" />&nbsp;&nbsp;';
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(val) + '" title="' + val + '" width="24" height="24" />&nbsp;&nbsp;';
});
instrumentHtml += '</div></td>';

View File

@ -25,7 +25,7 @@
instrumentHtml = '<td><div class="nowrap">';
var instruments = val.instruments.split("|");
$.each(instruments, function(index, instrument) {
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(instrument) + '" width="24" height="24" />&nbsp;';
instrumentHtml += '<img src="' + context.JK.getInstrumentIcon24(instrument) + '" title="' + instrument + '" width="24" height="24" />&nbsp;';
});
instrumentHtml += '</div></td>';

View File

@ -1072,6 +1072,15 @@
});
}
function deleteRecordingClaim(id) {
return $.ajax({
type: "DELETE",
dataType: "json",
contentType: 'application/json',
url: "/api/recordings/" + id + "/claim"
});
}
function claimRecording(options) {
var recordingId = options["id"];
@ -1437,6 +1446,7 @@
this.getClaimedRecording = getClaimedRecording;
this.updateClaimedRecording = updateClaimedRecording;
this.deleteClaimedRecording = deleteClaimedRecording;
this.deleteRecordingClaim = deleteRecordingClaim;
this.claimRecording = claimRecording;
this.startPlayClaimedRecording = startPlayClaimedRecording;
this.stopPlayClaimedRecording = stopPlayClaimedRecording;

View File

@ -25,6 +25,8 @@
var $uploadPercent = $('#recording-manager-upload .percent', $parentElement);
var $convertCommand = $('#recording-manager-convert', $parentElement);
var $convertPercent = $('#recording-manager-convert .percent', $parentElement);
var $deleteCommand = $('#recording-manager-delete', $parentElement);
var $deletePercent = $('#recording-manager-delete .percent', $parentElement);
var $fileManager = $('#recording-manager-launcher', $parentElement);
if($fileManager.length == 0) {throw "no file manager element"; }
@ -32,12 +34,14 @@
$downloadCommand.data('command-type', 'download')
$uploadCommand.data('command-type', 'upload')
$convertCommand.data('command-type', 'convert')
$deleteCommand.data('command-type', 'delete')
// keys come from backend
var lookup = {
SyncDownload: { command: $downloadCommand, percent: $downloadPercent},
SyncUpload: { command: $uploadCommand, percent: $uploadPercent},
SyncConvert: { command: $convertCommand, percent: $convertPercent}
SyncConvert: { command: $convertCommand, percent: $convertPercent},
SyncDelete: { command: $deleteCommand, percent: $deletePercent}
}
var $self = $(this);

View File

@ -1237,7 +1237,7 @@
$languageList = $screen.find('#session-language-list');
$sessionPlusMusiciansLabel = $screen.find('label[for="session-plus-musicians"]');
$editScheduledSessions = $screen.find('#edit_scheduled_sessions');
$btnSelectFiles = $screen.find('.btn-select-files');
$btnSelectFiles = $screen.find('#session-notation-file-selection');
$selectedFilenames = $screen.find('#selected-filenames');
$uploadSpinner = $screen.find('#file-upload-spinner');
$policyTypes = $screen.find('input[name="session-policy-type"]');

View File

@ -135,8 +135,7 @@
});
if (showJoinLink) {
// wire up the Join Link to the T&Cs dialog
// wire up the Join Link to the T&Cs dialog
$('.join-link', $parentRow).click(function(evt) {
if(!context.JK.guardAgainstBrowser(app)) {
return false;

View File

@ -138,23 +138,9 @@
return;
}
if ("invitations" in session) {
var invitation;
// user has invitations for this session
for (var i=0; i < session.invitations.length; i++) {
invitation = session.invitations[i];
// session contains an invitation for this user
if (invitation.receiver_id === context.JK.currentUserId) {
hasInvitation = true;
break;
}
}
}
if (session) {
// if user has an invitation, always open terms and allow joining regardless of settings
if (hasInvitation) {
logger.debug("Found invitation for user " + context.JK.currentUserId + ", session " + sessionId);
if (session.can_join) {
logger.debug("Found invitation or approved RSVP for user " + context.JK.currentUserId + ", session " + sessionId);
openJoinSessionTerms(sessionId);
}
else {

View File

@ -14,7 +14,10 @@ context.JK.SyncViewer = class SyncViewer
@downloadCommandId = null
@downloadMetadata = null
@uploadCommandId = null
@uploadMetadata = null;
@uploadMetadata = null
@cleanupCommandId = null
@cleanupMetadata = null
init: () =>
@root = $($('#template-sync-viewer').html())
@ -330,12 +333,15 @@ context.JK.SyncViewer = class SyncViewer
for clientInfo in recording.local_tracks
$track = @list.find(".recorded-track[data-recording-id='#{recording.recording_id}'][data-client-track-id='#{clientInfo.client_track_id}']")
$track.data('client-info', clientInfo)
$track.data('total-size', recording.size)
$track = @list.find(".mix[data-recording-id='#{recording.recording_id}']")
$track.data('client-info', recording.mix)
$track.data('total-size', recording.size)
$track = @list.find(".stream-mix[data-recording-id='#{recording.recording_id}']")
$track.data('client-info', recording.stream_mix)
$track.data('total-size', recording.size)
displayStreamMixHover: ($streamMix) =>
$clientState = $streamMix.find('.client-state')
@ -470,10 +476,10 @@ context.JK.SyncViewer = class SyncViewer
sendCommand: ($retry, cmd) =>
if context.JK.CurrentSessionModel and context.JK.CurrentSessionModel.inSession()
context.JK.confirmBubble($retry, 'sync-viewer-paused', {}, {offsetParent: $retry.closest('.dialog')})
context.JK.ackBubble($retry, 'sync-viewer-paused', {}, {offsetParent: $retry.closest('.dialog')})
else
context.jamClient.OnTrySyncCommand(cmd)
context.JK.confirmBubble($retry, 'sync-viewer-retry', {}, {offsetParent: $retry.closest('.dialog')})
context.JK.ackBubble($retry, 'sync-viewer-retry', {}, {offsetParent: $retry.closest('.dialog')})
retryDownloadRecordedTrack: (e) =>
@ -564,7 +570,7 @@ context.JK.SyncViewer = class SyncViewer
exportRecording: (e) =>
$export = $(e.target)
if context.JK.CurrentSessionModel and context.JK.CurrentSessionModel.inSession()
context.JK.confirmBubble($export, 'sync-viewer-paused', {}, {offsetParent: $export.closest('.dialog')})
context.JK.ackBubble($export, 'sync-viewer-paused', {}, {offsetParent: $export.closest('.dialog')})
return
recordingId = $export.closest('.details').attr('data-recording-id')
@ -573,7 +579,7 @@ context.JK.SyncViewer = class SyncViewer
cmd =
{ type: 'export_recording',
action: 'export'
action: 'export',
queue: 'upload',
recording_id: recordingId}
@ -581,9 +587,60 @@ context.JK.SyncViewer = class SyncViewer
context.jamClient.OnTrySyncCommand(cmd)
return false;
deleteRecording: (e) =>
$delete = $(e.target)
if context.JK.CurrentSessionModel and context.JK.CurrentSessionModel.inSession()
context.JK.ackBubble($delete, 'sync-viewer-paused', {}, {offsetParent: $delete.closest('.dialog')})
return
$details = $delete.closest('.details')
recordingId = $details.attr('data-recording-id')
if !recordingId? or recordingId == ""
throw "deleteRecording can't find data-recording-id"
context.JK.Banner.showYesNo({
title: "Confirm Deletion",
html: "Are you sure you want to delete this recording?",
yes: =>
@rest.deleteRecordingClaim(recordingId).done((response)=>
cmd =
{ type: 'recording_directory',
action: 'delete',
queue: 'cleanup',
recording_id: recordingId}
# now check if the sync is gone entirely, allowing us to delete it from the UI
@rest.getUserSync({user_sync_id: recordingId}).done((userSync) =>
# the user sync is still here. tell user it'll be done as soon as they've uploaded their files
context.JK.ackBubble($delete, 'file-sync-delayed-deletion', {}, {offsetParent: $delete.closest('.dialog')})
)
.fail((xhr) =>
if xhr.status == 404
# the userSync is gone; remove from file manager dynamically
$recordingHolder = $details.closest('.recording-holder')
$recordingHolder.slideUp()
else
@app.ajaxError(arguments)
)
context.jamClient.OnTrySyncCommand(cmd)
)
.fail(@app.ajaxError)
})
return false;
displaySize: (size) =>
# size is in bytes. divide by million, anxosd round to one decimal place
megs = Math.round(size * 10 / (1024 * 1024) ) / 10
"#{megs}M"
createRecordingWrapper: ($toWrap, recordingInfo) =>
totalSize = $($toWrap.get(0)).data('total-size')
recordingInfo.recording_landing_url = "/recordings/#{recordingInfo.id}"
recordingInfo.totalSize = this.displaySize(totalSize)
recordingInfo.claimedRecordingId = recordingInfo.my?.id
$wrapperDetails = $(context._.template(@templateRecordingWrapperDetails.html(), recordingInfo, {variable: 'data'}))
$wrapper = $('<div class="recording-holder"></div>')
$toWrap.wrapAll($wrapper)
@ -595,6 +652,7 @@ context.JK.SyncViewer = class SyncViewer
$wrapper.append(this.createMix('fake', recordingInfo))
$wrapper.find('a.export').click(this.exportRecording)
$wrapper.find('a.delete').click(this.deleteRecording)
separateByRecording: () =>
$recordedTracks = @list.find('.sync')
@ -747,6 +805,10 @@ context.JK.SyncViewer = class SyncViewer
this.renderUploadRecordedTrack(commandId, commandMetadata)
else
this.renderGeneric(commandId, 'upload', commandMetadata)
else if commandMetadata.queue == 'cleanup'
@cleanupCommandId = commandId
@cleanupMetadata = commandMetadata
renderSingleRecording: (userSyncs) =>
return if userSyncs.entries.length == 0
@ -813,6 +875,9 @@ context.JK.SyncViewer = class SyncViewer
recordingId = @uploadMetadata['recording_id']
this.updateSingleRecording(recordingId) if recordingId?
else if commandId == @cleanupCommandId
this.logResult(@cleanupMetadata, success, reason, false)
else
@logger.error("unknown commandId in renderFinishCommand")
@ -849,7 +914,8 @@ context.JK.SyncViewer = class SyncViewer
$matchingStreamMix = @list.find(".stream-mix.sync[data-recording-id='#{recordingId}']")
if $matchingStreamMix.length > 0
this.updateProgressOnSync($matchingStreamMix, 'upload', percentage)
else if commandId == @cleanupCommandId
# ignore
else
@logger.error("unknown commandId in renderFinishCommand")
@ -860,7 +926,7 @@ context.JK.SyncViewer = class SyncViewer
commandType = data['commandType']
commandMetadata = data['commandMetadata']
category = commandType == 'download' ? 'download' : 'upload'
category = commandMetadata.queue
if category == 'download' && (@downloadCommandId != null && @downloadCommandId != commandId)
@logger.warn("received command-start for download but previous command did not send stop")
@ -876,17 +942,20 @@ context.JK.SyncViewer = class SyncViewer
commandId = data['commandId']
if commandId == @downloadCommandId
category = 'download'
this.renderFinishCommand(commandId, data)
@downloadCommandId = null
@downloadMetadata = null;
else if commandId == @uploadCommandId
category = 'upload'
this.renderFinishCommand(commandId, data)
@uploadCommandId = null
@uploadMetadata = null;
@uploadMetadata = null
else if commandId == @cleanupCommandId
this.renderFinishCommand(commandId, data)
@cleanupCommandId = null
@cleanupMetadata = null
else
@logger.warn("received command-stop for unknown command: #{commandId} #{@downloadCommandId} #{@uploadCommandId}" )
@logger.warn("received command-stop for unknown command: #{commandId} #{@downloadCommandId} #{@uploadCommandId} #{@cleanupCommandId}" )
fileManagerCmdProgress: (e, data) =>
#console.log("fileManagerCmdProgress", data)
@ -899,6 +968,8 @@ context.JK.SyncViewer = class SyncViewer
else if commandId == @uploadCommandId
category = 'upload'
this.renderPercentage(commandId, category, data.percentage)
else if commandId == @cleanupCommandId
# do nothing
else
@logger.warn("received command-percentage for unknown command")
@ -918,6 +989,8 @@ context.JK.SyncViewer = class SyncViewer
return 'CLEANUP TRACK'
else if metadata.type == 'stream_mix' && metadata.action == 'upload'
return 'UPLOADING STREAM MIX'
else if metadata.type == 'recording_directory' && metadata.action == 'delete'
return 'DELETE RECORDING'
else
return "#{metadata.action} #{metadata.type}".toUpperCase()
@ -938,6 +1011,7 @@ context.JK.SyncViewer = class SyncViewer
when 'no-match-in-queue' then 'restart JamKazam'
when 'already-done' then 'ignored, already done'
when 'failed-convert' then 'failed previously'
when 'minimum-protection-time' then 'too soon to delete'
else reason
displaySuccess = if success then 'yes' else 'no'

View File

@ -149,7 +149,7 @@
* @param data (optional) data for your template, if applicable
* @param options (optional) You can override the default BeautyTips options: https://github.com/dillon-sellars/BeautyTips
*/
context.JK.confirmBubble = function($element, templateName, data, options) {
context.JK.ackBubble = function($element, templateName, data, options) {
if(!options) options = {};
options.spikeGirth = 0;
options.spikeLength = 0;

View File

@ -10,7 +10,7 @@
&.musician-bubble {
width:425px;
width:438px;
}
h2 {

View File

@ -8,6 +8,9 @@
left: 17%;
width: 50%;
#recording-manager-delete {
display:none;
}
// if it's the native client, then show the File Manager span. if it's not (normal browser) hide it.
// even if it's the native client, once a command is running, hide File Manager
&.native-client {

View File

@ -73,6 +73,24 @@
margin-top:4px;
}
}
label[for="keep"] {
display: inline;
float:right;
line-height: 26px;
padding-right: 5px;
vertical-align: middle;
}
select[name="keep"] {
float:right;
}
div[purpose="keep"] {
clear:both;
float:right;
.icheckbox_minimal {
float:right;
margin-top:4px;
}
}

View File

@ -40,5 +40,13 @@
}
clear: left;
}
.google_login_button {
vertical-align: middle;
}
.signed_in_to_google {
color: yellow;
}
}

View File

@ -194,13 +194,23 @@
.export {
float:right;
margin-right:3px;
margin-right:10px;
font-size:12px;
}
.timeago {
float:right;
font-size:12px;
}
.totalsize {
float:right;
margin-right:10px;
font-size:12px;
}
.delete {
float:right;
margin-right:10px;
font-size:12px;
}
}
.log-list {

View File

@ -30,7 +30,7 @@ class ApiClaimedRecordingsController < ApiController
raise PermissionError, 'only owner of claimed_recording can update it'
end
@claimed_recording.discard(current_user)
render :json => {}, :status => 200
respond_with @claimed_recording
end
def download

View File

@ -1,6 +1,7 @@
class ApiRecordingsController < ApiController
before_filter :api_signed_in_user, :except => [ :add_like ]
before_filter :lookup_recording, :only => [ :show, :stop, :claim, :discard, :keep ]
before_filter :lookup_recording, :only => [ :show, :stop, :claim, :discard, :keep, :delete_claim ]
before_filter :lookup_recorded_track, :only => [ :download, :upload_next_part, :upload_sign, :upload_part_complete, :upload_complete ]
before_filter :lookup_recorded_video, :only => [ :video_upload_sign, :video_upload_start, :video_upload_complete ]
before_filter :lookup_stream_mix, :only => [ :upload_next_part_stream_mix, :upload_sign_stream_mix, :upload_part_complete_stream_mix, :upload_complete_stream_mix ]
@ -94,6 +95,20 @@ class ApiRecordingsController < ApiController
end
end
def delete_claim
claim = @recording.claim_for_user(current_user)
if claim
claim.discard(current_user)
if claim.errors.any?
response.status = :unprocessable_entity
respond_with claim
end
end
respond_with @recording
end
def add_comment
if params[:id].blank?
render :json => { :message => "Recording ID is required" }, :status => 400
@ -229,118 +244,8 @@ class ApiRecordingsController < ApiController
else
render :status => 422
end
end
def upload_next_part_stream_mix
length = params[:length]
md5 = params[:md5]
@quick_mix.upload_next_part(length, md5)
if @quick_mix.errors.any?
response.status = :unprocessable_entity
# this is not typical, but please don't change this line unless you are sure it won't break anything
# this is needed because after_rollback in the RecordedTrackObserver touches the model and something about it's
# state doesn't cause errors to shoot out like normal.
render :json => { :errors => @quick_mix.errors }, :status => 422
else
result = {
:part => @quick_mix.next_part_to_upload,
:offset => @quick_mix.file_offset.to_s
}
render :json => result, :status => 200
end
end
def upload_sign_stream_mix
render :json => @quick_mix.upload_sign(params[:md5]), :status => 200
end
def upload_part_complete_stream_mix
part = params[:part]
offset = params[:offset]
@quick_mix.upload_part_complete(part, offset)
if @quick_mix.errors.any?
response.status = :unprocessable_entity
respond_with @quick_mix
else
render :json => {}, :status => 200
end
end
def upload_complete_stream_mix
@quick_mix.upload_complete
if @quick_mix.errors.any?
response.status = :unprocessable_entity
respond_with @quick_mix
return
else
render :json => {}, :status => 200
end
end
def upload_next_part_stream_mix
length = params[:length]
md5 = params[:md5]
@quick_mix.upload_next_part(length, md5)
if @quick_mix.errors.any?
response.status = :unprocessable_entity
# this is not typical, but please don't change this line unless you are sure it won't break anything
# this is needed because after_rollback in the RecordedTrackObserver touches the model and something about it's
# state doesn't cause errors to shoot out like normal.
render :json => { :errors => @quick_mix.errors }, :status => 422
else
result = {
:part => @quick_mix.next_part_to_upload,
:offset => @quick_mix.file_offset.to_s
}
render :json => result, :status => 200
end
end
def upload_sign_stream_mix
render :json => @quick_mix.upload_sign(params[:md5]), :status => 200
end
def upload_part_complete_stream_mix
part = params[:part]
offset = params[:offset]
@quick_mix.upload_part_complete(part, offset)
if @quick_mix.errors.any?
response.status = :unprocessable_entity
respond_with @quick_mix
else
render :json => {}, :status => 200
end
end
def upload_complete_stream_mix
@quick_mix.upload_complete
if @quick_mix.errors.any?
response.status = :unprocessable_entity
respond_with @quick_mix
return
else
render :json => {}, :status => 200
end
end
def upload_next_part_stream_mix
length = params[:length]
md5 = params[:md5]

View File

@ -38,4 +38,9 @@ class ApiUserSyncsController < ApiController
@next = data[:next]
render "api_user_syncs/index", :layout => nil
end
def deletables
data = UserSync.deletables({user_id:current_user.id, recording_ids: params[:recording_ids]})
render json: {recording_ids: data}, status: 200
end
end

View File

@ -5,8 +5,8 @@ class RecordingsController < ApplicationController
def show
@claimed_recording = ClaimedRecording.find_by_id(params[:id])
if @claimed_recording.nil?
recording = Recording.find(params[:id])
@claimed_recording = recording.candidate_claimed_recording
recording = Recording.find_by_id(params[:id])
@claimed_recording = recording.candidate_claimed_recording if recording
end
render :layout => "web"
end

View File

@ -150,6 +150,10 @@ class SessionsController < ApplicationController
render 'oauth_complete', :layout => "landing"
end
def has_google_auth
render :json => {has_google_auth: (!!current_user && !!UserAuthorization.google_auth(current_user).first)}
end
def redirect_after_signin(default)
redirect_to(params['redirect-to'].blank? ? default : params['redirect-to'])
end

View File

@ -25,20 +25,27 @@ module MusicSessionHelper
else
unique_users = music_session.unique_users
if sharer && unique_users.exists?(sharer)
"LIVE SESSION: #{sharer.name}#{additional_member_count(unique_users)}"
"LIVE SESSION: #{sharer.name}#{additional_member_count(unique_users, sharer)}"
else
"LIVE SESSION: #{music_session.creator.name}#{additional_member_count(unique_users)}"
"LIVE SESSION: #{music_session.creator.name}#{additional_member_count(unique_users, music_session.creator)}"
end
end
end
def additional_member_count(unique_users)
def additional_member_count(unique_users, target_user)
length = unique_users.length
if length < 2
""
else
" & #{length} OTHERS"
other_length = length - 1
if other_length == 1
other_user_in_array = unique_users - [target_user]
other_user = other_user_in_array[0]
" & #{other_user.name}"
else
" & #{length - 1} OTHERS"
end
end
end

View File

@ -23,22 +23,29 @@ module RecordingHelper
if claimed_recording.recording.band
"RECORDING: #{claimed_recording.recording.band.name}"
else
unique_users = claimed_recording.recording.users
if sharer && unique_users.exists?(sharer)
"RECORDING: #{sharer.name}#{additional_member_count(unique_users)}"
unique_users = claimed_recording.recording.users.uniq
if sharer && unique_users.include?(sharer)
"RECORDING: #{sharer.name}#{additional_member_count(unique_users, sharer)}"
else
"RECORDING: #{claimed_recording.user.name}#{additional_member_count(unique_users)}"
"RECORDING: #{claimed_recording.user.name}#{additional_member_count(unique_users, claimed_recording.user)}"
end
end
end
def additional_member_count(unique_users)
def additional_member_count(unique_users, target_user)
length = unique_users.length
if length < 2
""
else
" & #{length} OTHERS"
other_length = length - 1
if other_length == 1
other_user_in_array = unique_users - [target_user]
other_user = other_user_in_array[0]
" & #{other_user.name}"
else
" & #{length - 1} OTHERS"
end
end
end

View File

@ -4,7 +4,7 @@
object @claimed_recording
attributes :id, :name, :description, :is_public, :genre_id
attributes :id, :name, :description, :is_public, :genre_id, :discarded
node :share_url do |claimed_recording|
unless claimed_recording.share_token.nil?

View File

@ -78,7 +78,7 @@ glue :recording do
'recording'
end
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :has_mix?, :mix_state
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :has_mix?, :mix_state, :when_will_be_discarded?
node do |recording|
{

View File

@ -15,6 +15,10 @@ else
attributes :id, :name, :description, :musician_access, :approval_required, :fan_access, :fan_chat, :band_id, :user_id, :claimed_recording_initiator_id, :track_changes_counter, :max_score
node :can_join do |session|
session.can_join?(current_user, true)
end
node :genres do |item|
[item.genre.description] # XXX: need to return single genre; not array
end

View File

@ -21,6 +21,10 @@ else
:language, :recurring_mode, :language_description, :scheduled_start_date, :access_description, :timezone, :timezone_id, :timezone_description,
:musician_access_description, :fan_access_description, :session_removed_at, :legal_policy, :open_rsvps, :is_unstructured_rsvp?
node :can_join do |session|
session.can_join?(current_user, true)
end
node :share_url do |history|
unless history.share_token.nil?
share_token_url(history.share_token.token)

View File

@ -1,6 +1,6 @@
object @recording
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :when_will_be_discarded?
node :mix do |recording|
if recording.mix

View File

@ -129,7 +129,7 @@
<script type="text/template" id="template-help-sync-viewer-paused">
<div class="help-sync-viewer-paused">
JamKazam prevents file uploads, downloads, and recording exports while in a session.
JamKazam prevents file uploads, downloads, and recording management while in a session.
</div>
</script>
@ -139,5 +139,21 @@
</div>
</script>
<script type="text/template" id="template-help-recording-discarded-soon">
<div class="help-recording-discarded-soon">
This recording will be discarded {% $.timeago(data.discardTime) %}. If you want to keep this recording, click the (edit) link.
</div>
</script>
<script type="text/template" id="template-help-command-enqueued">
<div class="help-recording-command-enqueued">
Your request will be executed as soon as possible.
</div>
</script>
<script type="text/template" id="template-help-file-sync-delayed-deletion">
<div class="file-sync-delayed-deletion">
The files associated with this recording will be deleted as soon as your client has uploaded your tracks and stream mix from this recording.
</div>
</script>

View File

@ -11,4 +11,7 @@
<span id="recording-manager-download" class="recording-manager-command">
<span>downloading</span><span class="percent">0</span>
</span>
<span id="recording-manager-delete" class="recording-manager-command-hidden">
<span>delete</span><span class="percent">0</span>
</span>
</span>

View File

@ -204,7 +204,7 @@
<div>
<div class="spinner-small upload-spinner" id="file-upload-spinner"></div>
<div class="select-files-section">
<a class="button-orange btn-select-files" href="#">SELECT FILES...</a>
<a id="session-notation-file-selection" class="button-orange btn-select-files" href="#">SELECT FILES...</a>
<input type="file" class="hidden" id="session-select-files" value="Select Files..."
accept=".pdf, .png, .jpg, .jpeg, .gif, .xml, .mxl, .txt" multiple>
</div>

View File

@ -88,12 +88,16 @@ script type="text/template" id='template-sync-viewer-no-syncs'
| You have no recordings.
script type="text/template" id="template-sync-viewer-recording-wrapper-details"
.details data-recording-id="{{data.id}}"
.details data-recording-id="{{data.id}}" data-claimed-recording-id="{{data.claimedRecordingId}}"
a.session-detail-page href="{{data.recording_landing_url}}" rel="external"
span.name
| {{data.my ? data.my.name : 'Unknown Name'}}
span.timeago
| {{$.timeago(data.created_at)}}
span.totalsize
| SIZE: {{data.totalSize}}
a.delete href="#"
| DELETE
a.export href="#"
| EXPORT

View File

@ -1,24 +0,0 @@
.dialog.configure-tracks{ layout: 'dialog', 'layout-id' => 'edit-recording', id: 'edit-recording-dialog'}
.content-head
= image_tag "content/icon_add.png", {:width => 19, :height => 19, :class => 'content-icon' }
%h1 Edit Recording
.dialog-inner
%form
.field
%label{for: 'name'} Recording name:
%input{type: 'text', name: 'name'}
.field
%label{for: 'description'} Description:
%textarea{name: 'description', rows: '4'}
.field.genre-selector
%label{for: 'genre'} Genre:
%select{name:'genre'}
.field{purpose: 'is_public'}
%input{type: 'checkbox', name: 'is_public'}
%label{for: 'is_public'} Public Recording
.buttons
%a.button-grey.cancel-btn {'layout-action' => 'cancel'} CANCEL
%a.button-orange.delete-btn DELETE
%a.button-orange.save-btn UPDATE
%br{clear: 'all'}

View File

@ -0,0 +1,26 @@
#edit-recording-dialog.dialog.configure-tracks layout='dialog' layout-id='edit-recording'
.content-head
= image_tag "content/icon_add.png", {:width => 19, :height => 19, :class => 'content-icon' }
h1 Edit Recording
.dialog-inner
form
.field
label for='name' Recording name:
input type='text' name='name'
.field
label for='description' Description:
textarea name='description' rows='4'
.field.genre-selector
label for='genre' Genre:
select name='genre'
.field purpose='is_public'
input type='checkbox' name='is_public'
label for='is_public' Public Recording
.buttons
.left
a.button-grey.cancel-btn layout-action='cancel' CANCEL
.right
a.button-orange.delete-btn DELETE
a.button-orange.save-btn UPDATE
br clear='all'

View File

@ -23,12 +23,16 @@
.field.w100.left{:purpose => "description"}
%label{:for => "description"} Description:
%textarea#claim-recording-description.w100{:name => "description"}
.field.left{:purpose => "save_video"}
%input{:checked => "checked", :name => "save_video", :type => "checkbox"}/
%label{:for => "save_video"} Save Video to Computer
.field.left{:purpose => "upload_to_youtube"}
%input{:checked => "checked", :name => "upload_to_youtube", :type => "checkbox"}/
%label{:for => "upload_to_youtube"} Upload Video to YouTube
/ TODO VRFS-1849: Uncomment this when rest of feature developed:
/ .field.left{:purpose => "save_video"}
/ %input{:checked => "checked", :name => "save_video", :type => "checkbox"}/
/ %label{:for => "save_video"} Save Video to Computer
/ .field.left{:purpose => "upload_to_youtube"}
/ %span
/ %input{:checked => "checked", :name => "upload_to_youtube", :type => "checkbox"}/
/ %label{:for => "upload_to_youtube"} Upload Video to YouTube
/ %span
/ = render(:partial => "shared/google_login")
.field.left{:purpose => "is_public"}
%input{:checked => "checked", :name => "is_public", :type => "checkbox"}/
%label{:for => "is_public"} Public Recording

View File

@ -30,6 +30,7 @@
<% else %>
<%= render "layouts/social_meta" %>
<% end %>
<%= yield(:extra_js) %>
</head>
<body class="jam" data-client-type="<%= @nativeClient ? 'client' : 'browser' %>">
<%= yield %>

View File

@ -18,7 +18,7 @@
<% end %>
<div class="recordings-page">
<% if @claimed_recording.is_public || @claimed_recording.recording.has_access?(current_user) %>
<% if !@claimed_recording.recording.deleted && (@claimed_recording.is_public || @claimed_recording.recording.has_access?(current_user)) %>
<div class="landing-band">
<% unless @claimed_recording.recording.band.blank? %>
<div class="landing-avatar">
@ -97,7 +97,7 @@
<% end %>
</div>
<% if @claimed_recording.is_public || @claimed_recording.recording.has_access?(current_user) %>
<% if !@claimed_recording.recording.deleted && (@claimed_recording.is_public || @claimed_recording.recording.has_access?(current_user)) %>
<% if signed_in? %>
<% unless @claimed_recording.recording.band.nil? %>
<%= render :partial => "shared/landing_sidebar", :locals => {:user => @claimed_recording.recording.band, :recent_history => @claimed_recording.recording.band.recent_history} %>

View File

@ -0,0 +1,26 @@
-content_for :extra_js do
javascript:
// Check for google authorization using AJAX and show/hide the
// google login button / "signed in" label as appropriate:
$(window).on('focus', function() {
$.ajax({
type: "GET",
dataType: "json",
url: "/auth/has_google_auth"
}).success(function(data) {
if(data.has_google_auth) {
$("input.google_login_button").addClass("hidden")
$("span.signed_in_to_google").removeClass("hidden")
if (window._oauth_win) {
window._oauth_win.close()
}
} else {
$("span.signed_in_to_google").addClass("hidden")
$("input.google_login_button").removeClass("hidden")
}
})
});
-google_auth = (current_user.nil?) ? nil : !!JamRuby::UserAuthorization.google_auth(current_user).first
span.signed_in_to_google class=((!google_auth) ? "hidden" : "") ="(Signed in)"
input.google_login_button class=((google_auth) ? "hidden" : "") type='image' onclick='window._oauth_win = window.open("/auth/google_login", "_blank", "height=500,width=500,menubar=no,resizable=no,status=no");' src="/assets/google_signin.png" height="30px"

View File

@ -7,7 +7,7 @@
/ type and artist
.left.ml20.w15
.title
%a{:href => "/recordings/{{data.candidate_claimed_recording.id}}", :rel => "external", :hoveraction => "recording", :'recording-id' => '{{data.candidate_claimed_recording.id}}'} RECORDING
%a.title-text{:href => "/recordings/{{data.candidate_claimed_recording.id}}", :rel => "external", :hoveraction => "recording", :'recording-id' => '{{data.candidate_claimed_recording.id}}'} RECORDING
%a.edit-recording-dialog{href: "#"} (edit)
.artist
%a.artist{:hoveraction => '{{data.feed_item.helpers.artist_hoveraction}}', :profileaction => "{{data.feed_item.helpers.artist_hoveraction}}", :'{{data.feed_item.helpers.artist_datakey}}' => '{{data.feed_item.helpers.artist_id}}'}

View File

@ -152,6 +152,9 @@ if defined?(Bundler)
config.multipass_callback_url = "http://jamkazam.desk.com/customer/authentication/multipass/callback"
end
config.desk_multipass_key = "453ddfc0bab00130a9c13bc9a68cf24c" # found in https://jamkazam.desk.com/admin/channels/support-center/auth_settings
config.desk_multipass_site = "jamkazam" # found in https://jamkazam.desk.com/admin/channels/support-center/auth_settings
# perf_data configs
config.perf_data_signed_url_timeout = 3600 * 24 # 1 day
@ -273,5 +276,7 @@ if defined?(Bundler)
config.scoring_timeout_threshold = 5 # how many consequetive bad scores before you are put into the doghouse
config.scoring_get_work_interval = 1000 # how much time between normal getwork requests
config.scoring_get_work_backoff_interval = 60 * 1000 # how much time between failed getwork requests
config.recordings_stale_time = 3 # num days of inactivity before we decide that a recording is no longer going to be claimed
end
end

View File

@ -30,6 +30,7 @@ SampleApp::Application.routes.draw do
# oauth
match '/auth/:provider/callback', :to => 'sessions#oauth_callback'
match '/auth/failure', :to => 'sessions#failure'
match '/auth/has_google_auth', :to => 'sessions#has_google_auth'
# session info page
match '/sessions/:id/details' => 'music_sessions#session_info', :via => :get, :as => 'music_scheduled_session_detail'
@ -335,6 +336,7 @@ SampleApp::Application.routes.draw do
# downloads/uploads
match '/users/:id/syncs' => 'api_user_syncs#index', :via => :get
match '/users/:id/syncs/:user_sync_id' => 'api_user_syncs#show', :via => :get
match '/users/:id/syncs/deletables' => 'api_user_syncs#deletables', :via => :post
# bands
@ -413,6 +415,7 @@ SampleApp::Application.routes.draw do
match '/recordings/:id' => 'api_recordings#show', :via => :get, :as => 'api_recordings_detail'
match '/recordings/:id/stop' => 'api_recordings#stop', :via => :post, :as => 'api_recordings_stop'
match '/recordings/:id/claim' => 'api_recordings#claim', :via => :post, :as => 'api_recordings_claim'
match '/recordings/:id/claim' => 'api_recordings#delete_claim', :via => :delete, :as => 'api_recordings_delete_claim'
match '/recordings/:id/comments' => 'api_recordings#add_comment', :via => :post, :as => 'api_recordings_add_comment'
match '/recordings/:id/likes' => 'api_recordings#add_like', :via => :post, :as => 'api_recordings_add_like'
match '/recordings/:id/discard' => 'api_recordings#discard', :via => :post, :as => 'api_recordings_discard'

View File

@ -57,4 +57,9 @@ ActiveMusicSessionCleaner:
ScoreHistorySweeper:
cron: 0 * * * *
class: "JamRuby::ScoreHistorySweeper"
description: "Creates 'ScoreHistory' tables from Scores"
description: "Creates 'ScoreHistory' tables from Scores"
RecordingsCleaner:
cron: 0 * * * *
class: "JamRuby::RecordingsCleaner"
description: "Cleans up recordings that no one wants after 7 days"

View File

@ -25,6 +25,12 @@ describe ApiUserSyncsController do
json[:entries].length.should == 0
end
it "deletables" do
post :deletables, { :format => 'json', :id => user1.id, recording_ids: ['1'] }
json = JSON.parse(response.body, :symbolize_names => true)
json[:recording_ids].should eq(['1'])
end
describe "one recording with two users" do
let!(:recording1) {
recording = FactoryGirl.create(:recording, owner: user1, band: nil, duration:1)
@ -40,23 +46,12 @@ describe ApiUserSyncsController do
}
it "no claimed_recordings" do
# every is supposed to upload immediately, but no downloads until you try claim it. The assertions below validate this
# if there are no claims, then no one wants the recording. no usersyncs
get :index, { :format => 'json', :id => user1.id }
json = JSON.parse(response.body, :symbolize_names => true)
json[:next].should be_nil
json[:entries].length.should == 2
recorded_track1 = json[:entries][0]
recorded_track1[:upload][:should_upload].should be_true
recorded_track1[:upload][:too_many_upload_failures].should be_false
recorded_track1[:download][:should_download].should be_false
recorded_track1[:download][:too_many_downloads].should be_false
recorded_track2 = json[:entries][1]
recorded_track2[:upload][:should_upload].should be_true
recorded_track2[:upload][:too_many_upload_failures].should be_false
recorded_track2[:download][:should_download].should be_false
recorded_track2[:download][:too_many_downloads].should be_false
json[:entries].length.should == 0
end
it "recording isn't over" do
@ -73,6 +68,9 @@ describe ApiUserSyncsController do
FactoryGirl.create(:claimed_recording, user: user1, recording: recording1, discarded:false)
recording1.recorded_tracks[0].fully_uploaded = false
recording1.recorded_tracks[0].save!
get :index, { :format => 'json', :id => user1.id }
json = JSON.parse(response.body, :symbolize_names => true)
json[:next].should be_nil
@ -94,7 +92,7 @@ describe ApiUserSyncsController do
get :index, { :format => 'json', :id => user2.id }
json = JSON.parse(response.body, :symbolize_names => true)
json[:next].should be_nil
json[:entries].length.should == 2
json[:entries].length.should == 1
recorded_track1 = json[:entries][0]
recorded_track1[:upload][:should_upload].should be_true
@ -102,32 +100,17 @@ describe ApiUserSyncsController do
recorded_track1[:download][:should_download].should be_false
recorded_track1[:download][:too_many_downloads].should be_false
recorded_track2 = json[:entries][1]
recorded_track2[:upload][:should_upload].should be_true
recorded_track2[:upload][:too_many_upload_failures].should be_false
recorded_track2[:download][:should_download].should be_false
recorded_track2[:download][:too_many_downloads].should be_false
end
it "one user decides to discard the recording" do
FactoryGirl.create(:claimed_recording, user: user1, recording: recording1, discarded:true)
FactoryGirl.create(:claimed_recording, user: user2, recording: recording1, discarded:false)
# it's a length of zero because recorded_tracks default to 'fully_uploaded = true'. so nothing to do for this user
get :index, { :format => 'json', :id => user1.id }
json = JSON.parse(response.body, :symbolize_names => true)
json[:next].should be_nil
json[:entries].length.should == 2
recorded_track1 = json[:entries][0]
recorded_track1[:upload][:should_upload].should be_true
recorded_track1[:upload][:too_many_upload_failures].should be_false
recorded_track1[:download][:should_download].should be_false
recorded_track1[:download][:too_many_downloads].should be_false
recorded_track2 = json[:entries][1]
recorded_track2[:upload][:should_upload].should be_true
recorded_track2[:upload][:too_many_upload_failures].should be_false
recorded_track2[:download][:should_download].should be_false
recorded_track2[:download][:too_many_downloads].should be_false
json[:entries].length.should == 0
controller.current_user = user2
get :index, { :format => 'json', :id => user2.id }
@ -135,16 +118,17 @@ describe ApiUserSyncsController do
json[:next].should be_nil
json[:entries].length.should == 2
recorded_track1 = json[:entries][0]
recorded_track1[:upload][:should_upload].should be_true
recorded_track1[:upload][:too_many_upload_failures].should be_false
recorded_track1[:download][:should_download].should be_false
recorded_track1[:download][:should_download].should be_true
recorded_track1[:download][:too_many_downloads].should be_false
recorded_track2 = json[:entries][1]
recorded_track2[:upload][:should_upload].should be_true
recorded_track2[:upload][:too_many_upload_failures].should be_false
recorded_track2[:download][:should_download].should be_false
recorded_track2[:download][:should_download].should be_true
recorded_track2[:download][:too_many_downloads].should be_false
end

View File

@ -60,11 +60,18 @@ describe MusicSessionHelper do
describe "additional_member_count" do
it "no unique users" do
helper.additional_member_count([]).should == ""
helper.additional_member_count([], @user).should == ""
end
it "has 2 users" do
helper.additional_member_count(['', '']).should == " & 2 OTHERS"
user2 = FactoryGirl.create(:user)
helper.additional_member_count([@user, user2], @user).should == " & #{user2.name}"
end
it "has 3 users" do
user2 = FactoryGirl.create(:user)
user3 = FactoryGirl.create(:user)
helper.additional_member_count([@user, user2, user3], @user).should == " & 2 OTHERS"
end
end
end

View File

@ -79,15 +79,45 @@ describe MusicSessionHelper do
result.start_with?("RECORDING").should be_true
result.end_with?(@claimed_recording.user.name).should be_true
end
# regression: https://jamkazam.atlassian.net/browse/VRFS-2468
it "correct number of others when multiple tracks for 2 users" do
second_user = FactoryGirl.create(:user)
track1 = FactoryGirl.create(:recorded_track, user: second_user, recording: @recording)
track2 = FactoryGirl.create(:recorded_track, user: second_user, recording: @recording)
result = helper.title_for_claimed_recording(@claimed_recording)
result.include?("& #{second_user.name}").should be_true
end
# regression: https://jamkazam.atlassian.net/browse/VRFS-2468
it "correct number of others when multiple tracks for 3 users" do
second_user = FactoryGirl.create(:user)
track1 = FactoryGirl.create(:recorded_track, user: second_user, recording: @recording)
track2 = FactoryGirl.create(:recorded_track, user: second_user, recording: @recording)
third_user = FactoryGirl.create(:user)
track1 = FactoryGirl.create(:recorded_track, user: third_user, recording: @recording)
track2 = FactoryGirl.create(:recorded_track, user: third_user, recording: @recording)
result = helper.title_for_claimed_recording(@claimed_recording)
result.include?("& 2 OTHERS").should be_true
end
end
describe "additional_member_count" do
it "no unique users" do
helper.additional_member_count([]).should == ""
helper.additional_member_count([], @user).should == ""
end
it "has 2 users" do
helper.additional_member_count(['', '']).should == " & 2 OTHERS"
user2 = FactoryGirl.create(:user)
helper.additional_member_count([@user, user2], @user).should == " & #{user2.name}"
end
it "has 3 users" do
user2 = FactoryGirl.create(:user)
user3 = FactoryGirl.create(:user)
helper.additional_member_count([@user, user2, user3], @user).should == " & 2 OTHERS"
end
end
end