VRFS-1654 issue fixed without test

This commit is contained in:
Bert Owen 2014-05-09 23:50:50 +08:00
commit 6ecb7abcad
192 changed files with 3978 additions and 2074 deletions

1
.gitignore vendored
View File

@ -6,4 +6,3 @@
HTML HTML
.DS_Store .DS_Store
coverage coverage

View File

@ -1,7 +1,7 @@
source 'http://rubygems.org' source 'http://rubygems.org'
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/'
devenv = ENV["BUILD_NUMBER"].nil? # Jenkins sets a build number environment variable devenv = ENV["BUILD_NUMBER"].nil? || ENV["TEST_WWW"] == "1"
if devenv if devenv
gem 'jam_db', :path=> "../db/target/ruby_package" gem 'jam_db', :path=> "../db/target/ruby_package"
@ -102,7 +102,6 @@ group :development, :test do
gem 'rspec-rails' gem 'rspec-rails'
gem 'guard-rspec', '0.5.5' gem 'guard-rspec', '0.5.5'
gem 'jasmine', '1.3.1' gem 'jasmine', '1.3.1'
# gem 'pry'
gem 'execjs', '1.4.0' gem 'execjs', '1.4.0'
gem 'therubyracer' #, '0.11.0beta8' gem 'therubyracer' #, '0.11.0beta8'
gem 'factory_girl_rails', '4.1.0' gem 'factory_girl_rails', '4.1.0'
@ -114,6 +113,9 @@ end
group :test do group :test do
gem 'simplecov', '~> 0.7.1' gem 'simplecov', '~> 0.7.1'
gem 'simplecov-rcov' gem 'simplecov-rcov'
gem 'capybara-webkit'
gem 'capybara-screenshot'
gem 'poltergeist'
end end
gem 'pry' gem 'pry'

View File

@ -20,7 +20,7 @@ ActiveAdmin.register_page "Dashboard" do
column do column do
panel "Recent Sessions" do panel "Recent Sessions" do
ul do ul do
MusicSessionHistory.order('created_at desc').limit(5).map do |music_session| MusicSession.order('created_at desc').limit(5).map do |music_session|
li do li do
text_node "'#{music_session.description}' created by #{User.find(music_session.user_id).name} at #{music_session.created_at}, " text_node "'#{music_session.description}' created by #{User.find(music_session.user_id).name} at #{music_session.created_at}, "
text_node " members: " text_node " members: "
@ -38,7 +38,7 @@ ActiveAdmin.register_page "Dashboard" do
end end
end end
end end
end end
end end
# column do # column do

View File

@ -3,36 +3,58 @@ ActiveAdmin.register_page 'Feed' do
# get user information via params # get user information via params
user_id = nil user_id = nil
user_id = params[:feed][:user_id] if params[:feed] user_id = params[:feed][:user_id] if params[:feed] && params[:feed][:user_id] != ''
user_name = User.find(user_id).name if user_id user_name = 'All'
user_name = "All" unless user_id user_name = User.find(user_id).to_label if user_id
render :partial => 'form', :locals => {param: params} render :partial => 'form', locals: {user_name: user_name, user_id: user_id }
offset = 0 page = (params[:page] ||= 1).to_i
limit = 10 per_page = 10
offset = (page - 1) * per_page
# get feed ids # get feed ids
where_sql = '' where_sql = ''
where_sql = "where user_id = '#{user_id}'" if user_id where_sql = "where user_id = '#{user_id}'" if user_id
sql_feed_ids = "SELECT id, 'music_session_histories' as type, created_at FROM music_sessions_history #{where_sql} sql_feed_ids = "SELECT id, 'music_sessions' as type, created_at FROM music_sessions #{where_sql}
UNION ALL UNION ALL
SELECT DISTINCT recording_id as id, 'recordings' as type, created_at FROM recorded_tracks #{where_sql} SELECT DISTINCT recording_id as id, 'recordings' as type, created_at FROM recorded_tracks #{where_sql}
UNION ALL UNION ALL
SELECT id, 'diagnostics' as type, created_at FROM diagnostics #{where_sql} SELECT id, 'diagnostics' as type, created_at FROM diagnostics #{where_sql}
ORDER BY created_at DESC ORDER BY created_at DESC
OFFSET #{offset} OFFSET #{offset}
LIMIT #{limit};" LIMIT #{per_page};"
models = [] sql_feed_count = "SELECT COUNT(*) FROM (
SELECT id, 'music_sessions' as type, created_at FROM music_sessions #{where_sql}
UNION ALL
SELECT DISTINCT recording_id as id, 'recordings' as type, created_at FROM recorded_tracks #{where_sql}
UNION ALL
SELECT id, 'diagnostics' as type, created_at FROM diagnostics #{where_sql}
ORDER BY created_at DESC
) AS IDS;"
feed_count = ActiveRecord::Base.connection.execute(sql_feed_count).values[0][0].to_i
id_types = ActiveRecord::Base.connection.execute(sql_feed_ids).values id_types = ActiveRecord::Base.connection.execute(sql_feed_ids).values
@feed_pages = WillPaginate::Collection.create(page, per_page) do |pager|
pager.total_entries = feed_count
pager.replace(id_types)
end
div class: 'feed-pagination' do
will_paginate @feed_pages
end
recordings = []
sessions = []
diagnostics = []
id_types.each do |id_and_type| id_types.each do |id_and_type|
if id_and_type[1] == "music_session_histories" if id_and_type[1] == "music_sessions"
models << JamRuby::MusicSessionHistory.find(id_and_type[0]) sessions << JamRuby::MusicSession.find(id_and_type[0])
# elsif id_and_type[1] == "recordings"
# models << JamRuby::Recording.find(id_and_type[0])
elsif id_and_type[1] == "recordings" elsif id_and_type[1] == "recordings"
models << JamRuby::Diagnostics.find(id_and_type[0]) recordings << JamRuby::Recording.find(id_and_type[0])
elsif id_and_type[1] == "diagnostics"
diagnostics << JamRuby::Diagnostic.find(id_and_type[0])
else else
raise "Unknown type returned from feed ids" raise "Unknown type returned from feed ids"
end end
@ -40,22 +62,160 @@ ActiveAdmin.register_page 'Feed' do
columns do columns do
column do column do
panel "Activity - #{user_name}" do panel "Music Sessions - #{user_name}" do
para id_types.inspect if sessions.count > 0
ul do table_for(sessions) do
models.each do |model| column :creator do |msh|
li do link_to msh.creator.to_label, admin_feed_path({feed: {user_id: msh.creator.id}})
text_node model.inspect
end end
column :created_at do |msh| msh.created_at.strftime('%b %d %Y, %H:%M') end
column :duration do |msh| "#{msh.duration_minutes.round(2)} minutes" end
column :members do |msh|
uu = msh.unique_users
if uu.length > 0
uu.each do |u|
span link_to u.to_label + ', ', admin_feed_path({feed: {user_id: u.id}})
end
else
span para 'No members'
end
end
column :band do |msh| auto_link(msh.band, msh.band.try(:name)) end
column :fan_access do |msh| msh.fan_access end
column :plays do |msh| msh.plays.count end
column :likes do |msh| msh.likes.count end
column :comments do |msh|
if msh.comment_count > 0
text_node "(#{msh.comment_count}) "
msh.comments.each do |comment|
text_node comment.user.to_label + ', '
end
else
span para 'No comments'
end
end
end
else
span class: 'text-center' do
para 'No session activities.'
end
end
end
panel "Recordings - #{user_name}" do
if recordings.count > 0
table_for(recordings) do
column :starter do |rec|
link_to rec.owner.to_label, admin_feed_path({feed: {user_id: rec.owner.id}})
end
column :mixes do |rec|
ul do
mixes = rec.mixes
if mixes.count > 0
mixes.each do |mix|
li do
text_node "Created At: #{mix.created_at.strftime('%b %d %Y, %H:%M')}, "
text_node "Started At: #{mix.started_at.strftime('%b %d %Y, %H:%M')}, "
text_node "Completed At: #{mix.completed_at.strftime('%b %d %Y, %H:%M')}, "
text_node "Error Count: #{mix.error_count}, "
text_node "Error Reason: #{mix.error_reason}, "
text_node "Error Detail: #{mix.error_detail}, "
text_node "Download Count: #{mix.download_count}, "
if !mix.nil? && !mix[:ogg_url].nil?
span link_to 'Download OGG', mix.sign_url(3600, 'ogg')
else
text_node 'OGG download not available'
end
if !mix.nil? && !mix[:mp3_url].nil?
span link_to 'Download MP3', mix.sign_url(3600, 'mp3')
else
text_node 'MP3 download not available'
end
end
end
else
span para 'No mixes'
end
end
end
column :recorded_tracks do |rec|
ul do
rts = rec.recorded_tracks
if rts.count > 0
rts.each do |gt|
li do
span link_to gt.musician.to_label, admin_feed_path({feed: {user_id: gt.musician.id}})
span ", #{gt.instrument_id}, "
span "Download Count: #{gt.download_count}, "
span "Fully uploaded: #{gt.fully_uploaded}, "
span "Upload failures: #{gt.upload_failures}, "
span "Part failures: #{gt.part_failures}, "
if gt[:url]
# span link_to 'Download', gt.sign_url(3600)
else
span 'No track available'
end
end
end
else
span para 'No recorded tracks'
end
end
end
column :claimed_recordings do |rec|
ul do
crs = rec.claimed_recordings
if crs.count > 0
crs.each do |cr|
li do
span cr.name
span link_to cr.user.to_label, admin_feed_path({feed: {user_id: cr.user.id}})
span ", Public: #{cr.is_public}"
end
end
else
span para 'No claimed recordings'
end
end
end
end
else
span class: 'text-center' do
para 'No recording activities.'
end
end
end
panel "Diagnostics - #{user_name}" do
if diagnostics.count > 0 then
table_for(diagnostics) do
column :user do |d|
span link_to d.user.to_label, admin_feed_path({feed: {user_id: d.user.id}})
end
column :created_at do |d| d.created_at.strftime('%b %d %Y, %H:%M') end
column :type
column :creator
column :data do |d|
span style: "white-space: pre;" do
if JSON.parse(d.data).all?
JSON.pretty_generate(JSON.parse(d.data))
else
d.data
end
end
end
end
else
span class: 'text-center' do
para 'No diagnostic activities.'
end end
end end
end end
end end
end end
end div class: 'feed-pagination' do
will_paginate @feed_pages
controller do
def index
end end
end end
end end

View File

@ -24,8 +24,8 @@ ActiveAdmin.register JamRuby::Mix, :as => 'Mixes' do
attributes_table_for(mix) do attributes_table_for(mix) do
row :recording do |mix| auto_link(mix.recording, mix.recording.id) end row :recording do |mix| auto_link(mix.recording, mix.recording.id) end
row :created_at do |mix| mix.created_at.strftime('%b %d %Y, %H:%M') end row :created_at do |mix| mix.created_at.strftime('%b %d %Y, %H:%M') end
# row :s3_url do |mix| mix.url end row :s3_url do |mix| mix.sign_url end
# row :manifest do |mix| mix.manifest end row :manifest do |mix| mix.manifest end
row :completed do |mix| "#{mix.completed ? "finished" : "not finished"}" end row :completed do |mix| "#{mix.completed ? "finished" : "not finished"}" end
if mix.completed if mix.completed
row :completed_at do |mix| mix.completed_at.strftime('%b %d %Y, %H:%M') end row :completed_at do |mix| mix.completed_at.strftime('%b %d %Y, %H:%M') end

View File

@ -1,4 +1,4 @@
ActiveAdmin.register JamRuby::MusicSessionHistory, :as => 'Music Session History' do ActiveAdmin.register JamRuby::MusicSession, :as => 'Music Session' do
config.filters = false config.filters = false
config.per_page = 50 config.per_page = 50
@ -9,14 +9,14 @@ ActiveAdmin.register JamRuby::MusicSessionHistory, :as => 'Music Session History
controller do controller do
def scoped_collection def scoped_collection
if params['admin'].blank? || '1' == params['admin'] if params['admin'].blank? || '1' == params['admin']
@music_session_histories ||= end_of_association_chain @music_sessions ||= end_of_association_chain
.includes([:user, :band]) .includes([:creator, :band])
.order('created_at DESC') .order('created_at DESC')
else else
@music_session_histories ||= end_of_association_chain @music_sessions ||= end_of_association_chain
.joins('INNER JOIN users AS uu ON uu.id = music_sessions_history.user_id') .joins('INNER JOIN users AS uu ON uu.id = music_sessions.user_id')
.where(['uu.admin = ?','f']) .where(['uu.admin = ?','f'])
.includes([:user, :band]) .includes([:creator, :band])
.order('created_at DESC') .order('created_at DESC')
end end
end end
@ -33,9 +33,9 @@ ActiveAdmin.register JamRuby::MusicSessionHistory, :as => 'Music Session History
row :description row :description
row :duration do |msh| "#{msh.duration_minutes} minutes" end row :duration do |msh| "#{msh.duration_minutes} minutes" end
row :active do |msh| msh.session_removed_at.nil? end row :active do |msh| msh.session_removed_at.nil? end
row :creator do |msh| auto_link(msh.user, msh.user.try(:email)) end row :creator do |msh| auto_link(msh.creator, msh.creator.try(:email)) end
row :band do |msh| auto_link(msh.band, msh.band.try(:name)) end row :band do |msh| auto_link(msh.band, msh.band.try(:name)) end
row :genres row :genre
end end
end end
end end

View File

@ -4,8 +4,13 @@
color:lightgray; color:lightgray;
} }
.text-center {
text-align: center;
}
.feed-pagination { .feed-pagination {
height: 20px; height: 20px;
margin-bottom: 15px;
.pagination { .pagination {
float: left !important; float: left !important;

View File

@ -1,6 +1,6 @@
<%= semantic_form_for :feed, url: admin_feed_path, method: :get do |f| %> <%= semantic_form_for :feed, url: admin_feed_path, method: :get do |f| %>
<%= f.inputs do %> <%= f.inputs do %>
<%= f.input :user, :as => :autocomplete, :url => autocomplete_user_email_admin_users_path, :input_html => { :id_element => "#feed_user_id" }%> <%= f.input :user, :as => :autocomplete, :url => autocomplete_user_email_admin_users_path, :input_html => { :id_element => "#feed_user_id" } %>
<%= f.input :user_id, :as => :hidden %> <%= f.input :user_id, :as => :hidden %>
<% end %> <% end %>
<% end %> <% end %>

View File

@ -1,23 +0,0 @@
<table class="index_table index">
<thead>
<tr>
<td>User Name - <%= @user_id %></td>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr class="odd">
<td>
<p>
<%= link_to admin_feed_path(feed: {user_id: user.id}) do %>
<%= user.name %>
<% end %></p>
</td>
</tr>
<% end %>
</tbody>
</table>
<div class="feed-pagination">
<%= will_paginate @users %>
</div>

0
admin/log/phantomjs.out Normal file
View File

View File

@ -23,7 +23,7 @@ FactoryGirl.define do
factory :single_user_session do factory :single_user_session do
after(:create) do |user, evaluator| after(:create) do |user, evaluator|
music_session = FactoryGirl.create(:music_session, :creator => user) music_session = FactoryGirl.create(:active_music_session, :creator => user)
connection = FactoryGirl.create(:connection, :user => user, :music_session => music_session) connection = FactoryGirl.create(:connection, :user => user, :music_session => music_session)
end end
end end
@ -46,4 +46,131 @@ FactoryGirl.define do
description { |n| "Instrument #{n}" } description { |n| "Instrument #{n}" }
end end
factory :genre, :class => JamRuby::Genre do
description { |n| "Genre #{n}" }
end
factory :music_session, :class => JamRuby::MusicSession do
sequence(:name) { |n| "Music Session #{n}" }
sequence(:description) { |n| "Music Session Description #{n}" }
fan_chat true
fan_access true
approval_required false
musician_access true
legal_terms true
language 'english'
legal_policy 'standard'
genre JamRuby::Genre.first
association :creator, :factory => :user
end
factory :music_session_user_history, :class => JamRuby::MusicSessionUserHistory do
ignore do
history nil
user nil
end
music_session_id { history.id }
user_id { user.id }
sequence(:client_id) { |n| "Connection #{n}" }
end
factory :recorded_track, :class => JamRuby::RecordedTrack do
instrument JamRuby::Instrument.first
sound 'stereo'
sequence(:client_id) { |n| "client_id-#{n}"}
sequence(:track_id) { |n| "track_id-#{n}"}
sequence(:client_track_id) { |n| "client_track_id-#{n}"}
md5 'abc'
length 1
fully_uploaded true
association :user, factory: :user
association :recording, factory: :recording
end
factory :recording, :class => JamRuby::Recording do
association :owner, factory: :user
association :music_session, factory: :active_music_session
factory :recording_with_track do
before(:create) { |recording|
recording.recorded_tracks << FactoryGirl.create(:recorded_track, recording: recording, user: recording.owner)
}
end
end
factory :claimed_recording, :class => JamRuby::ClaimedRecording do
sequence(:name) { |n| "name-#{n}" }
sequence(:description) { |n| "description-#{n}" }
is_public true
association :genre, factory: :genre
association :user, factory: :user
before(:create) { |claimed_recording|
claimed_recording.recording = FactoryGirl.create(:recording_with_track, owner: claimed_recording.user)
}
end
factory :mix, :class => JamRuby::Mix do
started_at Time.now
completed_at Time.now
ogg_md5 'abc'
ogg_length 1
sequence(:ogg_url) { |n| "recordings/ogg/#{n}" }
mp3_md5 'abc'
mp3_length 1
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)
}
end
factory :diagnostic, :class => JamRuby::Diagnostic do
type JamRuby::Diagnostic::NO_HEARTBEAT_ACK
creator JamRuby::Diagnostic::CLIENT
data Faker::Lorem.sentence
association :user, factory: :user
end
factory :active_music_session_no_user_history, :class => JamRuby::ActiveMusicSession do
association :creator, factory: :user
ignore do
name "My Music Session"
description "Come Music Session"
fan_chat true
fan_access true
approval_required false
musician_access true
legal_terms true
genre JamRuby::Genre.first
band nil
end
before(:create) do |session, evaluator|
music_session = FactoryGirl.create(:music_session, name: evaluator.name, description: evaluator.description, fan_chat: evaluator.fan_chat,
fan_access: evaluator.fan_access, approval_required: evaluator.approval_required, musician_access: evaluator.musician_access,
genre: evaluator.genre, creator: evaluator.creator, band: evaluator.band)
session.id = music_session.id
end
factory :active_music_session do
after(:create) { |session|
FactoryGirl.create(:music_session_user_history, :history => session.music_session, :user => session.creator)
}
factory :music_session_with_mount do
association :mount, :factory => :icecast_mount
end
end
end
end end

View File

@ -0,0 +1,81 @@
require 'spec_helper'
describe 'Feeds' do
subject { page }
before do
MusicSession.delete_all
Recording.delete_all
Diagnostic.delete_all
User.delete_all
end
let(:admin) { FactoryGirl.create(:admin) }
let(:user) { FactoryGirl.create(:user) }
let(:music_session) { FactoryGirl.create(:music_session, :creator => user) }
let(:recording) { FactoryGirl.create(:recording, :owner => user) }
let(:diagnostic) { FactoryGirl.create(:diagnostic, :user => user) }
describe 'empty dashboard' do
before do
visit admin_feed_path
end
it { should have_selector('h2', text: 'Feed') }
it 'has no feeds' do
should have_selector('p', text: 'No session activities.')
should have_selector('p', text: 'No recording activities.')
should have_selector('p', text: 'No diagnostic activities.')
end
describe 'admin enters user name' do
it 'auto-completes with email + full name', :js => true do
within('form.feed') do
fill_in 'feed_user', with: user.email[0..3]
end
page.execute_script %Q{ $('form.feed input#feed_user').trigger('focus') }
page.execute_script %Q{ $('form.feed input#feed_user').trigger('keydown') }
sleep 5
find('a.ui-corner-all', text: user.to_label).trigger(:click)
should have_selector('form.feed #feed_user', user.to_label)
should have_selector('form.feed #feed_user_id', user.id)
end
end
end
describe 'activities' do
before do
visit admin_feed_path
end
it 'shows session, recording, diagnostic' do
should have_selector("tr#jam_ruby_music_session_#{music_session.id}")
should have_selector("tr#jam_ruby_recording_#{recording.id}")
should have_selector("tr#jam_ruby_diagnostic_#{diagnostic.id}")
end
it 'shows activities for one user', :js => true do
within('form.feed') do
fill_in 'feed_user', with: user.email[0..3]
end
page.execute_script %Q{ $('form.feed input#feed_user').trigger('focus') }
page.execute_script %Q{ $('form.feed input#feed_user').trigger('keydown') }
sleep 5
find('a.ui-corner-all', text: user.to_label).trigger(:click)
should have_selector('form.feed #feed_user', user.to_label)
should have_selector('form.feed #feed_user_id', user.id)
find('form.feed').trigger(:submit)
should have_selector("tr#jam_ruby_music_session_#{music_session.id}")
should have_selector("tr#jam_ruby_recording_#{recording.id}")
should have_selector("tr#jam_ruby_diagnostic_#{diagnostic.id}")
end
end
end

View File

@ -22,6 +22,9 @@ require 'rspec/autorun'
# load capybara # load capybara
require 'capybara/rails' require 'capybara/rails'
require 'capybara/rspec'
require 'capybara-screenshot/rspec'
require 'capybara/poltergeist'
#include Rails.application.routes.url_helpers #include Rails.application.routes.url_helpers
@ -30,6 +33,11 @@ require 'capybara/rails'
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
Capybara.register_driver :poltergeist do |app|
driver = Capybara::Poltergeist::Driver.new(app, { debug: false, phantomjs_logger: File.open('log/phantomjs.out', 'w') })
end
Capybara.javascript_driver = :poltergeist
Capybara.default_wait_time = 10
RSpec.configure do |config| RSpec.configure do |config|
# ## Mock Framework # ## Mock Framework

View File

@ -0,0 +1,30 @@
module Snapshot
SS_PATH = 'snapshots.html'
def set_up_snapshot(filepath = SS_PATH)
@size = [1280, 720] #arbitrary
@file = File.new(filepath, "w+")
@file.puts "<HTML><BODY BGCOLOR=grey>"
@file.puts "<H1>Snapshot #{ENV["BUILD_NUMBER"]} - #{@size[0]}x#{@size[1]}</H1>"
end
def snapshot_example
page.driver.resize(@size[0], @size[1])
@file.puts "<H3>Example name: #{get_description}</H3><BR><BR>"
end
def snap!(title = get_description)
base64 = page.driver.render_base64(:png)
@file.puts '<H3>' + title + '</H3>'
@file.puts '<img alt="' + title +'" src="data:image/png;base64,' + base64 + '" />'
@file.puts '<BR><BR><BR>'
end
def tear_down_snapshot
@file.puts "</BODY></HTML>"
@file.close()
end
end

View File

@ -151,3 +151,5 @@ user_mods.sql
connection_stale_expire.sql connection_stale_expire.sql
rename_chat_messages.sql rename_chat_messages.sql
fix_connection_fields.sql fix_connection_fields.sql
session_ratings.sql
scheduled_sessions.sql

View File

@ -0,0 +1,151 @@
-- track the last measured audio gear latency
ALTER TABLE users ADD COLUMN audio_latency double precision;
-- begin moving all the fields traditionally on music_sessions to music_sessions_history
ALTER TABLE music_sessions_history ADD COLUMN scheduled_start TIMESTAMP WITH TIME ZONE;
ALTER TABLE music_sessions_history ADD COLUMN scheduled_duration INTERVAL;
ALTER TABLE music_sessions_history ADD COLUMN musician_access BOOLEAN NOT NULL DEFAULT TRUE;
ALTER TABLE music_sessions_history ADD COLUMN approval_required BOOLEAN NOT NULL DEFAULT FALSE;
ALTER TABLE music_sessions_history ADD COLUMN fan_chat BOOLEAN NOT NULL DEFAULT TRUE;
ALTER TABLE music_sessions_history ADD COLUMN genre_id VARCHAR(64) REFERENCES genres(id);
ALTER TABLE music_sessions_history ADD COLUMN legal_policy VARCHAR(255) NOT NULL DEFAULT 'standard';
ALTER TABLE music_sessions_history ADD COLUMN language VARCHAR(255) NOT NULL DEFAULT 'en';
ALTER TABLE music_sessions_history ADD COLUMN name TEXT;
-- get rid of genres in favor of just genre_id (no more multi-genres for a session)
UPDATE music_sessions_history SET name = description;
ALTER TABLE music_sessions_history ALTER COLUMN name SET NOT NULL;
-- production db has some null genres on older sessions
UPDATE music_sessions_history SET genres = 'rock' where genres = '';
UPDATE music_sessions_history SET genre_id = genres;
ALTER TABLE music_sessions_history ALTER COLUMN genre_id SET NOT NULL;
ALTER TABLE music_sessions_history DROP COLUMN genres;
-- likers should refer to id field of music_sessions_history (not music_session_id)
ALTER TABLE music_sessions_likers ADD COLUMN music_session_id2 VARCHAR(64) REFERENCES music_sessions_history(id) ON DELETE CASCADE;
-- production db has some bad data
DELETE from music_sessions_likers where music_session_id NOT IN (select id from music_sessions_history);
UPDATE music_sessions_likers SET music_session_id2 = music_session_id;
ALTER TABLE music_sessions_likers DROP COLUMN music_session_id;
ALTER TABLE music_sessions_likers RENAME COLUMN music_session_id2 to music_session_id;
-- comments should refer to id field of music_sessions_history (not music_session_id)
ALTER TABLE music_sessions_comments ADD COLUMN music_session_id2 VARCHAR(64) REFERENCES music_sessions_history(id) ON DELETE CASCADE;
-- production db has some bad data
DELETE from music_sessions_comments where music_session_id NOT IN (select id from music_sessions_history);
UPDATE music_sessions_comments SET music_session_id2 = music_session_id;
ALTER TABLE music_sessions_comments DROP COLUMN music_session_id;
ALTER TABLE music_sessions_comments RENAME COLUMN music_session_id2 to music_session_id;
-- user_history should refer to id field of music_sessions_history (not music_session_id)
ALTER TABLE music_sessions_user_history ADD COLUMN music_session_id2 VARCHAR(64) REFERENCES music_sessions_history(id) ON DELETE CASCADE;
-- production db has some bad data
DELETE from music_sessions_user_history where music_session_id NOT IN (select id from music_sessions_history);
UPDATE music_sessions_user_history SET music_session_id2 = music_session_id;
ALTER TABLE music_sessions_user_history DROP COLUMN music_session_id;
ALTER TABLE music_sessions_user_history RENAME COLUMN music_session_id2 to music_session_id;
-- get rid of display fields on music_sessions
ALTER TABLE music_sessions DROP COLUMN musician_access;
ALTER TABLE music_sessions DROP COLUMN fan_access;
ALTER TABLE music_sessions DROP COLUMN description;
ALTER TABLE music_sessions DROP COLUMN fan_chat;
ALTER TABLE music_sessions DROP COLUMN approval_required;
ALTER TABLE music_sessions DROP COLUMN band_id;
ALTER TABLE music_sessions_history ALTER COLUMN music_session_id DROP NOT NULL;
-- create RSVP slots
CREATE TABLE rsvp_slots (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
instrument_id VARCHAR(64) REFERENCES instruments (id),
proficiency_level VARCHAR(255) NOT NULL,
music_session_id VARCHAR(64) NOT NULL REFERENCES music_sessions_history (id) ON DELETE CASCADE,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
);
-- create RSVP requests
CREATE TABLE rsvp_requests (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
user_id VARCHAR(64) NOT NULL REFERENCES users (id) ON DELETE CASCADE,
rsvp_slot_id VARCHAR(64) NOT NULL REFERENCES rsvp_slots(id) ON DELETE CASCADE,
message TEXT,
chosen BOOLEAN DEFAULT FALSE,
canceled BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
);
CREATE TABLE recurring_sessions (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
description VARCHAR(8000),
scheduled_start TIMESTAMP WITH TIME ZONE,
scheduled_duration INTERVAL,
musician_access BOOLEAN NOT NULL,
approval_required BOOLEAN NOT NULL,
fan_chat BOOLEAN NOT NULL,
genre_id VARCHAR(64) REFERENCES genres(id),
legal_policy VARCHAR(255) NOT NULL DEFAULT 'standard',
language VARCHAR(255) NOT NULL DEFAULT 'en',
name TEXT,
user_id VARCHAR(64) NOT NULL REFERENCES users (id) ON DELETE CASCADE,
band_id VARCHAR(64) REFERENCES bands(id) ON DELETE CASCADE,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
);
ALTER TABLE music_sessions_history ADD COLUMN recurring_session_id VARCHAR(64) REFERENCES recurring_sessions(id);
-- make these 3 tables be LOGGED, and refer to music_sessions_history instead of music_sessions
DROP TABLE fan_invitations;
DROP TABLE invitations;
DROP TABLE join_requests;
CREATE TABLE fan_invitations (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
sender_id VARCHAR(64),
receiver_id VARCHAR(64),
music_session_id VARCHAR(64),
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
);
ALTER TABLE ONLY fan_invitations ADD CONSTRAINT fan_invitations_music_session_id_fkey FOREIGN KEY (music_session_id) REFERENCES music_sessions_history(id) ON DELETE CASCADE;
CREATE UNLOGGED TABLE join_requests (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
user_id VARCHAR(64),
music_session_id VARCHAR(64),
text VARCHAR(2000),
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL
);
ALTER TABLE ONLY join_requests ADD CONSTRAINT user_music_session_uniqkey UNIQUE (user_id, music_session_id);
ALTER TABLE ONLY join_requests ADD CONSTRAINT join_requests_music_session_id_fkey FOREIGN KEY (music_session_id) REFERENCES music_sessions_history(id) ON DELETE CASCADE;
-- INVITATIONS
--------------
CREATE UNLOGGED TABLE invitations (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
sender_id VARCHAR(64),
receiver_id VARCHAR(64),
music_session_id VARCHAR(64),
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW() NOT NULL,
join_request_id VARCHAR(64)
);
ALTER TABLE ONLY invitations ADD CONSTRAINT invitations_uniqkey UNIQUE (sender_id, receiver_id, music_session_id);
ALTER TABLE ONLY invitations ADD CONSTRAINT invitations_join_request_id_fkey FOREIGN KEY (join_request_id) REFERENCES join_requests(id) ON DELETE CASCADE;
ALTER TABLE ONLY invitations ADD CONSTRAINT invitations_music_session_id_fkey FOREIGN KEY (music_session_id) REFERENCES music_sessions_history(id) ON DELETE CASCADE;
-- finally, rename music_sessions and music_sessions_history to reflect true nature better
ALTER TABLE music_sessions RENAME TO active_music_sessions;
ALTER TABLE music_sessions_history RENAME TO music_sessions;
-- add fk to chat_messages so they delete cleanly when users are deleted
ALTER TABLE ONLY chat_messages ADD CONSTRAINT chat_messages_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
-- fix any promotionals
UPDATE promotionals SET latest_type = 'JamRuby::MusicSession' WHERE latest_type = 'JamRuby::MusicSessionHistory';

View File

@ -0,0 +1 @@
ALTER TABLE music_sessions_user_history ADD COLUMN rating_comment TEXT;

View File

@ -186,6 +186,7 @@ message LoginAck {
optional string music_session_id = 5; // the music session that the user was in very recently (likely due to dropped connection) optional string music_session_id = 5; // the music session that the user was in very recently (likely due to dropped connection)
optional bool reconnected = 6; // if reconnect_music_session_id is specified, and the server could log the user into that session, then true is returned. optional bool reconnected = 6; // if reconnect_music_session_id is specified, and the server could log the user into that session, then true is returned.
optional string user_id = 7; // the database user id optional string user_id = 7; // the database user id
optional int32 connection_expire_time = 8; // this is how long the server gives you before killing your connection entirely after missing heartbeats
} }
// route_to: server // route_to: server

View File

@ -4,7 +4,7 @@ unless ENV["LOCAL_DEV"] == "1"
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/'
end end
devenv = ENV["BUILD_NUMBER"].nil? # Jenkins sets a build number environment variable devenv = ENV["BUILD_NUMBER"].nil? || ENV["TEST_WWW"] == "1"
if devenv if devenv
gem 'jam_db', :path=> "../db/target/ruby_package" gem 'jam_db', :path=> "../db/target/ruby_package"

View File

@ -31,6 +31,7 @@ require "jam_ruby/lib/module_overrides"
require "jam_ruby/lib/s3_util" require "jam_ruby/lib/s3_util"
require "jam_ruby/lib/s3_manager" require "jam_ruby/lib/s3_manager"
require "jam_ruby/lib/profanity" require "jam_ruby/lib/profanity"
require "jam_ruby/lib/json_validator"
require "jam_ruby/lib/em_helper.rb" require "jam_ruby/lib/em_helper.rb"
require "jam_ruby/lib/nav.rb" require "jam_ruby/lib/nav.rb"
require "jam_ruby/resque/audiomixer" require "jam_ruby/resque/audiomixer"
@ -75,10 +76,11 @@ require "jam_ruby/models/artifact_update"
require "jam_ruby/models/band_invitation" require "jam_ruby/models/band_invitation"
require "jam_ruby/models/band_musician" require "jam_ruby/models/band_musician"
require "jam_ruby/models/connection" require "jam_ruby/models/connection"
require "jam_ruby/models/diagnostic"
require "jam_ruby/models/friendship" require "jam_ruby/models/friendship"
require "jam_ruby/models/music_session" require "jam_ruby/models/active_music_session"
require "jam_ruby/models/music_session_comment" require "jam_ruby/models/music_session_comment"
require "jam_ruby/models/music_session_history" require "jam_ruby/models/music_session"
require "jam_ruby/models/music_session_liker" require "jam_ruby/models/music_session_liker"
require "jam_ruby/models/music_session_user_history" require "jam_ruby/models/music_session_user_history"
require "jam_ruby/models/music_session_perf_data" require "jam_ruby/models/music_session_perf_data"

View File

@ -39,12 +39,12 @@ module JamRuby
# this simulates music_session destroy callbacks with activerecord # this simulates music_session destroy callbacks with activerecord
def before_destroy_music_session(music_session_id) def before_destroy_music_session(music_session_id)
music_session = MusicSession.find_by_id(music_session_id) music_session = ActiveMusicSession.find_by_id(music_session_id)
music_session.before_destroy if music_session music_session.before_destroy if music_session
end end
# reclaim the existing connection, if ip_address is not nil then perhaps a new address as well # reclaim the existing connection, if ip_address is not nil then perhaps a new address as well
def reconnect(conn, reconnect_music_session_id, ip_address) def reconnect(conn, reconnect_music_session_id, ip_address, connection_stale_time, connection_expire_time)
music_session_id = nil music_session_id = nil
reconnected = false reconnected = false
@ -86,7 +86,7 @@ module JamRuby
end end
sql =<<SQL sql =<<SQL
UPDATE connections SET (aasm_state, updated_at, music_session_id, joined_session_at) = ('#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression}) UPDATE connections SET (aasm_state, updated_at, music_session_id, joined_session_at, stale_time, expire_time) = ('#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression}, #{connection_stale_time}, #{connection_expire_time})
WHERE WHERE
client_id = '#{conn.client_id}' client_id = '#{conn.client_id}'
RETURNING music_session_id RETURNING music_session_id
@ -114,7 +114,6 @@ WHERE
aasm_state = '#{Connection::CONNECT_STATE.to_s}' aasm_state = '#{Connection::CONNECT_STATE.to_s}'
RETURNING music_session_id RETURNING music_session_id
SQL SQL
# @log.info("*** flag_connection_stale_with_client_id: client_id = #{client_id}; sql = #{sql}")
self.pg_conn.exec(sql) do |result| self.pg_conn.exec(sql) do |result|
# if we did update a client to stale, retriee music_session_id # if we did update a client to stale, retriee music_session_id
@ -127,24 +126,22 @@ SQL
end end
# flag connections as stale # flag connections as stale
def flag_stale_connections(max_seconds) def flag_stale_connections()
ConnectionManager.active_record_transaction do |connection_manager| ConnectionManager.active_record_transaction do |connection_manager|
conn = connection_manager.pg_conn conn = connection_manager.pg_conn
sql =<<SQL sql =<<SQL
SELECT count(user_id) FROM connections SELECT count(user_id) FROM connections
WHERE WHERE
updated_at < (NOW() - interval '#{max_seconds} second') AND updated_at < (NOW() - (interval '1 second' * stale_time))AND
aasm_state = '#{Connection::CONNECT_STATE.to_s}' aasm_state = '#{Connection::CONNECT_STATE.to_s}'
SQL SQL
conn.exec(sql) do |result| conn.exec(sql) do |result|
count = result.getvalue(0, 0) count = result.getvalue(0, 0)
# @log.info("flag_stale_connections: flagging #{count} stale connections")
if 0 < count.to_i if 0 < count.to_i
# @log.info("flag_stale_connections: flagging #{count} stale connections")
sql =<<SQL sql =<<SQL
UPDATE connections SET aasm_state = '#{Connection::STALE_STATE.to_s}' UPDATE connections SET aasm_state = '#{Connection::STALE_STATE.to_s}'
WHERE WHERE
updated_at < (NOW() - interval '#{max_seconds} second') AND updated_at < (NOW() - (interval '1 second' * stale_time)) AND
aasm_state = '#{Connection::CONNECT_STATE.to_s}' aasm_state = '#{Connection::CONNECT_STATE.to_s}'
SQL SQL
conn.exec(sql) conn.exec(sql)
@ -155,33 +152,31 @@ SQL
# NOTE this is only used for testing purposes; # NOTE this is only used for testing purposes;
# actual deletes will be processed in the websocket context which cleans up dependencies # actual deletes will be processed in the websocket context which cleans up dependencies
def expire_stale_connections(max_seconds) def expire_stale_connections()
self.stale_connection_client_ids(max_seconds).each { |cid| self.delete_connection(cid) } self.stale_connection_client_ids().each { |client| self.delete_connection(client[:client_id]) }
end end
# expiring connections in stale state, which deletes them # expiring connections in stale state, which deletes them
def stale_connection_client_ids(max_seconds) def stale_connection_client_ids()
client_ids = [] clients = []
ConnectionManager.active_record_transaction do |connection_manager| ConnectionManager.active_record_transaction do |connection_manager|
conn = connection_manager.pg_conn conn = connection_manager.pg_conn
sql =<<SQL sql =<<SQL
SELECT client_id, music_session_id, user_id FROM connections SELECT client_id, music_session_id, user_id, client_type FROM connections
WHERE WHERE
updated_at < (NOW() - interval '#{max_seconds} second') AND updated_at < (NOW() - (interval '1 second' * expire_time))
aasm_state = '#{Connection::STALE_STATE.to_s}'
SQL SQL
conn.exec(sql) do |result| conn.exec(sql) do |result|
result.each { |row| result.each { |row|
client_id = row['client_id'] client_id = row['client_id']
music_session_id = row['music_session_id'] music_session_id = row['music_session_id']
user_id = row['user_id'] user_id = row['user_id']
client_type = row['client_type']
client_ids << client_id clients << {client_id: client_id, music_session_id: music_session_id, client_type: client_type, user_id: user_id}
} }
end end
end end
client_ids clients
end end
@ -189,7 +184,7 @@ SQL
# this number is used by notification logic elsewhere to know # this number is used by notification logic elsewhere to know
# 'oh the user joined for the 1st time, so send a friend update', or # 'oh the user joined for the 1st time, so send a friend update', or
# 'don't bother because the user has connected somewhere else already' # 'don't bother because the user has connected somewhere else already'
def create_connection(user_id, client_id, ip_address, client_type, &blk) def create_connection(user_id, client_id, ip_address, client_type, connection_stale_time, connection_expire_time, &blk)
# validate client_type # validate client_type
raise "invalid client_type: #{client_type}" if client_type != 'client' && client_type != 'browser' raise "invalid client_type: #{client_type}" if client_type != 'client' && client_type != 'browser'
@ -221,8 +216,8 @@ SQL
lock_connections(conn) lock_connections(conn)
conn.exec("INSERT INTO connections (user_id, client_id, ip_address, client_type, addr, locidispid, aasm_state) VALUES ($1, $2, $3, $4, $5, $6, $7)", conn.exec("INSERT INTO connections (user_id, client_id, ip_address, client_type, addr, locidispid, aasm_state, stale_time, expire_time) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
[user_id, client_id, ip_address, client_type, addr, locidispid, Connection::CONNECT_STATE.to_s]).clear [user_id, client_id, ip_address, client_type, addr, locidispid, Connection::CONNECT_STATE.to_s, connection_stale_time, connection_expire_time]).clear
# we just created a new connection-if this is the first time the user has shown up, we need to send out a message to his friends # we just created a new connection-if this is the first time the user has shown up, we need to send out a message to his friends
conn.exec("SELECT count(user_id) FROM connections WHERE user_id = $1", [user_id]) do |result| conn.exec("SELECT count(user_id) FROM connections WHERE user_id = $1", [user_id]) do |result|
@ -280,7 +275,7 @@ SQL
# same for session-if we are down to the last participant, delete the session # same for session-if we are down to the last participant, delete the session
unless music_session_id.nil? unless music_session_id.nil?
before_destroy_music_session(music_session_id) before_destroy_music_session(music_session_id)
result = conn.exec("DELETE FROM music_sessions WHERE id = $1 AND 0 = (select count(music_session_id) FROM connections where music_session_id = $1)", [music_session_id]) result = conn.exec("DELETE FROM active_music_sessions WHERE id = $1 AND 0 = (select count(music_session_id) FROM connections where music_session_id = $1)", [music_session_id])
if result.cmd_tuples == 1 if result.cmd_tuples == 1
music_session_id = nil music_session_id = nil
end end
@ -321,12 +316,12 @@ SQL
if num_participants == 0 if num_participants == 0
# delete the music_session # delete the music_session
before_destroy_music_session(previous_music_session_id) before_destroy_music_session(previous_music_session_id)
conn.exec("DELETE from music_sessions WHERE id = $1", conn.exec("DELETE from active_music_sessions WHERE id = $1",
[previous_music_session_id]) do |result| [previous_music_session_id]) do |result|
if result.cmd_tuples == 1 if result.cmd_tuples == 1
# music session deleted! # music session deleted!
@log.debug("deleted music session #{previous_music_session_id}") @log.debug("deleted music session #{previous_music_session_id}")
JamRuby::MusicSessionHistory.removed_music_session(previous_music_session_id) JamRuby::MusicSession.removed_music_session(previous_music_session_id)
elsif 1 < result.cmd_tuples elsif 1 < result.cmd_tuples
msg = "music_sessions table data integrity violation; multiple rows found with music_session_id=#{previous_music_session_id}" msg = "music_sessions table data integrity violation; multiple rows found with music_session_id=#{previous_music_session_id}"
@log.error(msg) @log.error(msg)
@ -337,7 +332,7 @@ SQL
# there are still people in the session # there are still people in the session
#ensure that there is no active claimed recording if the owner of that recording left the session #ensure that there is no active claimed recording if the owner of that recording left the session
conn.exec("UPDATE music_sessions set claimed_recording_id = NULL, claimed_recording_initiator_id = NULL where claimed_recording_initiator_id = $1 and id = $2", conn.exec("UPDATE active_music_sessions set claimed_recording_id = NULL, claimed_recording_initiator_id = NULL where claimed_recording_initiator_id = $1 and id = $2",
[user_id, previous_music_session_id]) [user_id, previous_music_session_id])
end end

View File

@ -0,0 +1,15 @@
# This needs to be outside the module to work.
class JsonValidator < ActiveModel::EachValidator
# implement the method called during validation
def is_json?(value)
begin
!!JSON.parse(value)
rescue
false
end
end
def validate_each(record, attribute, value)
record.errors[attribute] << 'must be JSON' unless value.nil? || is_json?(value)
end
end

View File

@ -33,7 +33,7 @@ end
class NoProfanityValidator < ActiveModel::EachValidator class NoProfanityValidator < ActiveModel::EachValidator
# implement the method called during validation # implement the method called during validation
def validate_each(record, attribute, value) def validate_each(record, attribute, value)
record.errors[attribute] << 'cannot contain profanity' if Profanity.is_profane?(value) record.errors[attribute] << 'cannot contain profanity' if JamRuby::Profanity.is_profane?(value)
end end
end end

View File

@ -53,7 +53,7 @@ module JamRuby
end end
# create a login ack (login was successful) # create a login ack (login was successful)
def login_ack(public_ip, client_id, token, heartbeat_interval, music_session_id, reconnected, user_id) def login_ack(public_ip, client_id, token, heartbeat_interval, music_session_id, reconnected, user_id, connection_expire_time)
login_ack = Jampb::LoginAck.new( login_ack = Jampb::LoginAck.new(
:public_ip => public_ip, :public_ip => public_ip,
:client_id => client_id, :client_id => client_id,
@ -61,7 +61,8 @@ module JamRuby
:heartbeat_interval => heartbeat_interval, :heartbeat_interval => heartbeat_interval,
:music_session_id => music_session_id, :music_session_id => music_session_id,
:reconnected => reconnected, :reconnected => reconnected,
:user_id => user_id :user_id => user_id,
:connection_expire_time => connection_expire_time
) )
Jampb::ClientMessage.new( Jampb::ClientMessage.new(

View File

@ -0,0 +1,482 @@
module JamRuby
class ActiveMusicSession < ActiveRecord::Base
self.primary_key = 'id'
self.table_name = 'active_music_sessions'
attr_accessor :legal_terms, :max_score
belongs_to :claimed_recording, :class_name => "JamRuby::ClaimedRecording", :foreign_key => "claimed_recording_id", :inverse_of => :playing_sessions
belongs_to :claimed_recording_initiator, :class_name => "JamRuby::User", :inverse_of => :playing_claimed_recordings, :foreign_key => "claimed_recording_initiator_id"
has_one :music_session, :class_name => "JamRuby::MusicSession", :foreign_key => 'music_session_id'
has_one :mount, :class_name => "JamRuby::IcecastMount", :inverse_of => :music_session, :foreign_key => 'music_session_id'
belongs_to :creator, :class_name => 'JamRuby::User', :foreign_key => :user_id
has_many :connections, :class_name => "JamRuby::Connection", foreign_key: :music_session_id
has_many :users, :through => :connections, :class_name => "JamRuby::User"
has_many :recordings, :class_name => "JamRuby::Recording", :inverse_of => :music_session, foreign_key: :music_session_id
has_many :chats, :class_name => "JamRuby::ChatMessages", :foreign_key => "session_id"
validates :creator, :presence => true
validate :creator_is_musician
validate :no_new_playback_while_playing
after_create :started_session
after_destroy do |obj|
JamRuby::MusicSession.removed_music_session(obj.id)
end
#default_scope :select => "*, 0 as score"
def attributes
super.merge('max_score' => self.max_score)
end
def max_score
nil unless has_attribute?(:max_score)
read_attribute(:max_score).to_i
end
before_create :create_uuid
def create_uuid
#self.id = SecureRandom.uuid
end
def before_destroy
self.mount.destroy if self.mount
end
def creator_is_musician
unless creator.musician?
errors.add(:creator, ValidationMessages::MUST_BE_A_MUSICIAN)
end
end
def no_new_playback_while_playing
# if we previous had a claimed recording and are trying to set one
# and if also the previous initiator is different than the current one... it's a no go
if !claimed_recording_id_was.nil? && !claimed_recording_id.nil? &&
claimed_recording_initiator_id_was != claimed_recording_initiator_id
errors.add(:claimed_recording, ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS)
end
end
# returns an array of client_id's that are in this session
# if as_musician is nil, all connections in the session ,regardless if it's a musician or not or not
# you can also exclude a client_id from the returned set by setting exclude_client_id
def get_connection_ids(options = {})
as_musician = options[:as_musician]
exclude_client_id = options[:exclude_client_id]
where = { :music_session_id => self.id }
where[:as_musician] = as_musician unless as_musician.nil?
exclude = "client_id != '#{exclude_client_id}'"unless exclude_client_id.nil?
Connection.select(:client_id).where(where).where(exclude).map(&:client_id)
end
# This is a little confusing. You can specify *BOTH* friends_only and my_bands_only to be true
# If so, then it's an OR condition. If both are false, you can get sessions with anyone.
def self.index(current_user, options = {})
participants = options[:participants]
genres = options[:genres]
keyword = options[:keyword]
friends_only = options[:friends_only].nil? ? false : options[:friends_only]
my_bands_only = options[:my_bands_only].nil? ? false : options[:my_bands_only]
as_musician = options[:as_musician].nil? ? true : options[:as_musician]
query = ActiveMusicSession
.joins(
%Q{
INNER JOIN
music_sessions
ON
active_music_sessions.id = music_sessions.id
}
)
.joins(
%Q{
INNER JOIN
connections
ON
active_music_sessions.id = connections.music_session_id
}
)
.joins(
%Q{
LEFT OUTER JOIN
friendships
ON
connections.user_id = friendships.user_id
AND
friendships.friend_id = '#{current_user.id}'
}
)
.joins(
%Q{
LEFT OUTER JOIN
invitations
ON
invitations.music_session_id = active_music_sessions.id
AND
invitations.receiver_id = '#{current_user.id}'
}
)
.group(
%Q{
active_music_sessions.id
}
)
.order(
%Q{
SUM(CASE WHEN invitations.id IS NULL THEN 0 ELSE 1 END) DESC,
SUM(CASE WHEN friendships.user_id IS NULL THEN 0 ELSE 1 END) DESC,
active_music_sessions.created_at DESC
}
)
if as_musician
query = query.where(
%Q{
musician_access = true
OR
invitations.id IS NOT NULL
}
)
else
# if you are trying to join the session as a fan/listener,
# we have to have a mount, fan_access has to be true, and we have to allow for the reload of icecast to have taken effect
query = query.joins('INNER JOIN icecast_mounts ON icecast_mounts.music_session_id = active_music_sessions.id INNER JOIN icecast_servers ON icecast_mounts.icecast_server_id = icecast_servers.id')
query = query.where('music_sessions.fan_access = true')
query = query.where("(active_music_sessions.created_at < icecast_servers.config_updated_at)")
end
query = query.where("music_sessions.description like '%#{keyword}%'") unless keyword.nil?
query = query.where("connections.user_id" => participants.split(',')) unless participants.nil?
query = query.where("music_sessions.genre_id in (?)", genres) unless genres.nil?
if my_bands_only
query = query.joins(
%Q{
LEFT OUTER JOIN
bands_musicians
ON
bands_musicians.user_id = '#{current_user.id}'
}
)
end
if my_bands_only || friends_only
query = query.where(
%Q{
#{friends_only ? "friendships.user_id IS NOT NULL" : "false"}
OR
#{my_bands_only ? "bands_musicians.band_id = music_sessions.band_id" : "false"}
}
)
end
return query
end
# This is a little confusing. You can specify *BOTH* friends_only and my_bands_only to be true
# If so, then it's an OR condition. If both are false, you can get sessions with anyone.
# note, this is mostly the same as above but includes paging through the result and and scores.
# thus it needs the client_id...
def self.nindex(current_user, options = {})
client_id = options[:client_id]
participants = options[:participants]
genres = options[:genres]
keyword = options[:keyword]
friends_only = options[:friends_only].nil? ? false : options[:friends_only]
my_bands_only = options[:my_bands_only].nil? ? false : options[:my_bands_only]
as_musician = options[:as_musician].nil? ? true : options[:as_musician]
offset = options[:offset]
limit = options[:limit]
connection = Connection.where(client_id: client_id).first!
locidispid = connection.locidispid
query = ActiveMusicSession
.select("active_music_sessions.*, max(coalesce(current_scores.score, 1000)) as max_score") # 1000 is higher than the allowed max of 999
.joins(
%Q{
INNER JOIN
music_sessions
ON
active_music_sessions.id = music_sessions.id
}
)
.joins(
%Q{
INNER JOIN
connections
ON
active_music_sessions.id = connections.music_session_id
}
)
.joins(
%Q{
LEFT OUTER JOIN
current_scores
ON
current_scores.alocidispid = connections.locidispid
AND
current_scores.blocidispid = #{locidispid}
}
)
.joins(
%Q{
LEFT OUTER JOIN
friendships
ON
connections.user_id = friendships.user_id
AND
friendships.friend_id = '#{current_user.id}'
}
)
.joins(
%Q{
LEFT OUTER JOIN
invitations
ON
invitations.music_session_id = active_music_sessions.id
AND
invitations.receiver_id = '#{current_user.id}'
}
)
.group(
%Q{
active_music_sessions.id
}
)
.order(
%Q{
SUM(CASE WHEN invitations.id IS NULL THEN 0 ELSE 1 END) DESC,
SUM(CASE WHEN friendships.user_id IS NULL THEN 0 ELSE 1 END) DESC,
active_music_sessions.created_at DESC
}
)
if (offset)
query = query.offset(offset)
end
if (limit)
query = query.limit(limit)
end
if as_musician
query = query.where(
%Q{
musician_access = true
OR
music_sessions.user_id = '#{current_user.id}'
OR
invitations.id IS NOT NULL
}
)
else
# if you are trying to join the session as a fan/listener,
# we have to have a mount, fan_access has to be true, and we have to allow for the reload of icecast to have taken effect
query = query.joins('INNER JOIN icecast_mounts ON icecast_mounts.music_session_id = active_music_sessions.id INNER JOIN icecast_servers ON icecast_mounts.icecast_server_id = icecast_servers.id')
query = query.where('music_sessions.fan_access = true')
query = query.where("(active_music_sessions.created_at < icecast_servers.config_updated_at)")
end
query = query.where("music_sessions.description like '%#{keyword}%'") unless keyword.nil?
query = query.where("connections.user_id" => participants.split(',')) unless participants.nil?
query = query.where("music_sessions.genre_id in (?)", genres) unless genres.nil?
if my_bands_only
query = query.joins(
%Q{
LEFT OUTER JOIN
bands_musicians
ON
bands_musicians.user_id = '#{current_user.id}'
}
)
end
if my_bands_only || friends_only
query = query.where(
%Q{
#{friends_only ? "friendships.user_id IS NOT NULL" : "false"}
OR
#{my_bands_only ? "bands_musicians.band_id = music_sessions.band_id" : "false"}
}
)
end
return query
end
# Verifies that the specified user can join this music session
def can_join? user, as_musician
if as_musician
if !user.musician
return false # "a fan can not join a music session as a musician"
raise PermissionError, "a fan can not join a music session as a musician"
end
if self.musician_access
if self.approval_required
return self.invited_musicians.exists?(user)
else
return true
end
else
# the creator can always join, and the invited users can join
return self.creator == user || self.invited_musicians.exists?(user)
end
else
# it's a fan, and the only way a fan can join is if fan_access is true
return self.fan_access
end
end
# Verifies that the specified user can see this music session
def can_see? user
if self.musician_access || self.fan_access
true
else
self.creator == user || self.invited_musicians.exists?(user)
end
end
# Verifies that the specified user can delete this music session
def can_delete? user
# the creator can delete
self.creator == user
end
def access? user
music_session.part_of_session? user
end
def most_recent_recording
recordings.where(:music_session_id => self.id).order('created_at desc').limit(1).first
end
# is this music session currently recording?
def is_recording?
recordings.where(:duration => nil).count > 0
end
def is_playing_recording?
!self.claimed_recording.nil?
end
def recording
recordings.where(:duration => nil).first
end
# stops any active recording
def stop_recording
current_recording = self.recording
current_recording.stop unless current_recording.nil?
end
def claimed_recording_start(owner, claimed_recording)
self.claimed_recording = claimed_recording
self.claimed_recording_initiator = owner
self.save
end
def claimed_recording_stop
self.claimed_recording = nil
self.claimed_recording_initiator = nil
self.save
end
def invitations
music_session.invitations
end
def invited_musicians
music_session.invited_musicians
end
def join_requests
music_session.join_requests
end
def fan_invitations
music_session.fan_invitations
end
def to_s
description
end
def musician_access
music_session.musician_access
end
def fan_access
music_session.fan_access
end
def description
music_session.description
end
def genre
music_session.genre
end
def fan_chat
music_session.fan_chat
end
def band
music_session.band
end
def approval_required
music_session.approval_required
end
def tick_track_changes
self.track_changes_counter += 1
self.save!(:validate => false)
end
def connected_participant_count
Connection.where(:music_session_id => self.id,
:aasm_state => Connection::CONNECT_STATE.to_s,
:as_musician => true)
.count
end
def started_session
raise "active_music_sessions.id must be set by caller" unless self.id
# associate this active_music_session with the music_session formally
session = MusicSession.find(self.id)
session.active_music_session = self
session.save!
GoogleAnalyticsEvent.track_session_duration(self)
GoogleAnalyticsEvent.track_band_real_session(self)
end
def self.sync(session_history)
music_session = MusicSession.find_by_id(session_history.id)
if music_session.nil?
music_session = MusicSession.new
music_session.id = session_history.id
end
music_session.user_id = session_history.creator.id
music_session.band_id = session_history.band.id unless session_history.band.nil?
session_history.save!
end
end
end

View File

@ -44,8 +44,7 @@ module JamRuby
has_many :invitations, :inverse_of => :band, :class_name => "JamRuby::BandInvitation", :foreign_key => "band_id" has_many :invitations, :inverse_of => :band, :class_name => "JamRuby::BandInvitation", :foreign_key => "band_id"
# music_sessions # music_sessions
has_many :music_sessions, :class_name => "JamRuby::MusicSession", :foreign_key => "band_id" has_many :music_sessions, :class_name => "JamRuby::MusicSession", foreign_key: :band_id, :inverse_of => :band
has_many :music_session_history, :class_name => "JamRuby::MusicSessionHistory", :foreign_key => "band_id", :inverse_of => :band
# events # events
has_many :event_sessions, :class_name => "JamRuby::EventSession" has_many :event_sessions, :class_name => "JamRuby::EventSession"
@ -54,19 +53,19 @@ module JamRuby
acts_as_mappable acts_as_mappable
def liker_count def liker_count
return self.likers.size self.likers.size
end end
def follower_count def follower_count
return self.followers.size self.followers.size
end end
def recording_count def recording_count
return self.recordings.size self.recordings.size
end end
def session_count def session_count
return self.music_sessions.size self.music_sessions.size
end end
def recent_history def recent_history
@ -74,7 +73,7 @@ module JamRuby
.order('created_at DESC') .order('created_at DESC')
.limit(10) .limit(10)
msh = MusicSessionHistory.where(:band_id => self.id) msh = MusicSession.where(:band_id => self.id)
.order('created_at DESC') .order('created_at DESC')
.limit(10) .limit(10)

View File

@ -11,6 +11,7 @@ module JamRuby
belongs_to :user belongs_to :user
belongs_to :music_session belongs_to :music_session
validates :user, presence: true
validates :message, length: {minimum: 1, maximum: 255}, no_profanity: true validates :message, length: {minimum: 1, maximum: 255}, no_profanity: true
class << self class << self

View File

@ -7,7 +7,7 @@ module JamRuby
belongs_to :user, :class_name => "JamRuby::User", :inverse_of => :claimed_recordings belongs_to :user, :class_name => "JamRuby::User", :inverse_of => :claimed_recordings
belongs_to :genre, :class_name => "JamRuby::Genre" belongs_to :genre, :class_name => "JamRuby::Genre"
has_many :recorded_tracks, :through => :recording, :class_name => "JamRuby::RecordedTrack" has_many :recorded_tracks, :through => :recording, :class_name => "JamRuby::RecordedTrack"
has_many :playing_sessions, :class_name => "JamRuby::MusicSession" has_many :playing_sessions, :class_name => "JamRuby::ActiveMusicSession"
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "claimed_recording_id" has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "claimed_recording_id"
has_many :plays, :class_name => "JamRuby::PlayablePlay", :foreign_key => "claimed_recording_id", :dependent => :destroy has_many :plays, :class_name => "JamRuby::PlayablePlay", :foreign_key => "claimed_recording_id", :dependent => :destroy
has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id' has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id'

View File

@ -3,18 +3,20 @@ require 'aasm'
module JamRuby module JamRuby
class Connection < ActiveRecord::Base class Connection < ActiveRecord::Base
# client_types
TYPE_CLIENT = 'client'
TYPE_BROWSER = 'browser'
attr_accessor :joining_session attr_accessor :joining_session
self.primary_key = 'id' self.primary_key = 'id'
belongs_to :user, :class_name => "JamRuby::User" belongs_to :user, :class_name => "JamRuby::User"
belongs_to :music_session, :class_name => "JamRuby::MusicSession" belongs_to :music_session, :class_name => "JamRuby::ActiveMusicSession", foreign_key: :music_session_id
has_many :tracks, :class_name => "JamRuby::Track", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all has_many :tracks, :class_name => "JamRuby::Track", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all
validates :as_musician, :inclusion => {:in => [true, false]} validates :as_musician, :inclusion => {:in => [true, false]}
validates :client_type, :inclusion => {:in => ['client', 'browser']} validates :client_type, :inclusion => {:in => [TYPE_CLIENT, TYPE_BROWSER]}
validate :can_join_music_session, :if => :joining_session? validate :can_join_music_session, :if => :joining_session?
after_save :require_at_least_one_track_when_in_session, :if => :joining_session? after_save :require_at_least_one_track_when_in_session, :if => :joining_session?
after_create :did_create after_create :did_create

View File

@ -0,0 +1,89 @@
module JamRuby
class Diagnostic < ActiveRecord::Base
# occurs when the client does not see a heartbeat from the server in a while
NO_HEARTBEAT_ACK = 'NO_HEARTBEAT_ACK'
# occurs when the client sees the socket go down
WEBSOCKET_CLOSED_REMOTELY = 'WEBSOCKET_CLOSED_REMOTELY'
# occurs when the client makes the socket go down
WEBSOCKET_CLOSED_LOCALLY = 'WEBSOCKET_CLOSED_LOCALLY'
# occurs when the websocket-gateway has finally given up entirely on a connection with no heartbeats seen in a while
EXPIRED_STALE_CONNECTION = 'EXPIRED_STALE_CONNECTION'
# occurs when the websocket-gateway is trying to handle a heartbeat, but can't find any state for the user.
# this implies a coding error
MISSING_CLIENT_STATE = 'MISSING_CLIENT_STATE'
# websocket gateway did not recognize message. indicates out-of-date websocket-gateway
UNKNOWN_MESSAGE_TYPE = 'UNKNOWN_MESSAGE_TYPE'
# empty route_to in message; which is invalid. indicates programming error
MISSING_ROUTE_TO = 'MISSING_ROUTE_TO'
# websocket gateway got a client with the same client_id as an already-connected client
DUPLICATE_CLIENT = 'DUPLICATE_CLIENT'
DIAGNOSTIC_TYPES = [NO_HEARTBEAT_ACK, WEBSOCKET_CLOSED_REMOTELY, EXPIRED_STALE_CONNECTION,
MISSING_CLIENT_STATE, UNKNOWN_MESSAGE_TYPE, MISSING_ROUTE_TO,
DUPLICATE_CLIENT, WEBSOCKET_CLOSED_LOCALLY]
# creator types #
CLIENT = 'client'
WEBSOCKET_GATEWAY = 'websocket-gateway'
CREATORS = [CLIENT, WEBSOCKET_GATEWAY]
self.primary_key = 'id'
self.inheritance_column = 'nothing'
belongs_to :user, :inverse_of => :diagnostics, :class_name => "JamRuby::User", :foreign_key => "user_id"
validates :user, :presence => true
validates :type, :inclusion => {:in => DIAGNOSTIC_TYPES}
validates :creator, :inclusion => {:in => CREATORS}
validates :data, length: {maximum: 100000}
def self.expired_stale_connection(user, context)
Diagnostic.save(EXPIRED_STALE_CONNECTION, user, WEBSOCKET_GATEWAY, context.to_json) if user
end
def self.missing_client_state(user, context)
Diagnostic.save(MISSING_CLIENT_STATE, user, WEBSOCKET_GATEWAY, context.to_json) if user
end
def self.missing_connection(user, context)
Diagnostic.save(MISSING_CONNECTION, user, WEBSOCKET_GATEWAY, context.to_json) if user
end
def self.duplicate_client(user, context)
Diagnostic.save(DUPLICATE_CLIENT, user, WEBSOCKET_GATEWAY, context.to_json) if user
end
def self.unknown_message_type(user, client_msg)
Diagnostic.save(UNKNOWN_MESSAGE_TYPE, user, WEBSOCKET_GATEWAY, client_msg.to_json) if user
end
def self.missing_route_to(user, client_msg)
Diagnostic.save(MISSING_ROUTE_TO, user, WEBSOCKET_GATEWAY, client_msg.to_json) if user
end
def self.save(type, user, creator, data)
diagnostic = Diagnostic.new
if user.class == String
diagnostic.user_id = user
else
diagnostic.user = user
end
diagnostic.data = data
diagnostic.type = type
diagnostic.creator = creator
diagnostic.save
end
end
end

View File

@ -13,7 +13,7 @@ module JamRuby
VAR_LAST_NAME = '@LASTNAME' VAR_LAST_NAME = '@LASTNAME'
DEFAULT_SENDER = "noreply@jamkazam.com" DEFAULT_SENDER = "noreply@jamkazam.com"
BATCH_SIZE = 1000 BATCH_SIZE = 5
BODY_TEMPLATE =<<FOO BODY_TEMPLATE =<<FOO
Hello #{VAR_FIRST_NAME}, Hello #{VAR_FIRST_NAME},

View File

@ -38,7 +38,7 @@ class JamRuby::EventSession < ActiveRecord::Base
# ideally this is based on some proper association with the event, not such a slushy time grab # ideally this is based on some proper association with the event, not such a slushy time grab
def sessions def sessions
if ready_display if ready_display
query = MusicSessionHistory.where(fan_access: true).where(created_at: (self.starts_at - 12.hours)..(self.ends_at + 12.hours)) query = MusicSession.where(fan_access: true).where(created_at: (self.starts_at - 12.hours)..(self.ends_at + 12.hours))
if self.user_id if self.user_id
query = query.where(user_id: self.user_id) query = query.where(user_id: self.user_id)
elsif self.band_id elsif self.band_id

View File

@ -7,7 +7,7 @@ module JamRuby
self.primary_key = 'id' self.primary_key = 'id'
belongs_to :sender, :inverse_of => :sent_fan_invitations, :class_name => "JamRuby::User", :foreign_key => "sender_id" belongs_to :sender, :inverse_of => :sent_fan_invitations, :class_name => "JamRuby::User", :foreign_key => "sender_id"
belongs_to :receiver, :inverse_of => :received_fan_invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id" belongs_to :receiver, :inverse_of => :received_fan_invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id"
belongs_to :music_session, :inverse_of => :fan_invitations, :class_name => "JamRuby::MusicSession" belongs_to :music_session, :inverse_of => :fan_invitations, :class_name => "JamRuby::MusicSession", :foreign_key => "music_session_id"
validates :sender, :presence => true validates :sender, :presence => true
validates :receiver, :presence => true validates :receiver, :presence => true
@ -18,7 +18,7 @@ module JamRuby
private private
def require_sender_in_music_session def require_sender_in_music_session
unless music_session.users.exists? sender unless music_session.part_of_session? sender
errors.add(:music_session, MEMBERSHIP_REQUIRED_OF_MUSIC_SESSION) errors.add(:music_session, MEMBERSHIP_REQUIRED_OF_MUSIC_SESSION)
end end
end end

View File

@ -3,12 +3,12 @@ module JamRuby
class Feed < ActiveRecord::Base class Feed < ActiveRecord::Base
belongs_to :recording, class_name: "JamRuby::Recording", inverse_of: :feed, foreign_key: 'recording_id' belongs_to :recording, class_name: "JamRuby::Recording", inverse_of: :feed, foreign_key: 'recording_id'
belongs_to :music_session_history, class_name: "JamRuby::MusicSessionHistory", inverse_of: :feed, foreign_key: 'music_session_id' belongs_to :music_session, class_name: "JamRuby::MusicSession", inverse_of: :feed, foreign_key: 'music_session_id'
FIXNUM_MAX = (2**(0.size * 8 -2) -1) FIXNUM_MAX = (2**(0.size * 8 -2) -1)
SORT_TYPES = ['date', 'plays', 'likes'] SORT_TYPES = ['date', 'plays', 'likes']
TIME_RANGES = { "today" => 1 , "week" => 7, "month" => 30, "all" => 0} TIME_RANGES = { "today" => 1 , "week" => 7, "month" => 30, "all" => 0}
TYPE_FILTERS = ['music_session_history', 'recording', 'all'] TYPE_FILTERS = ['music_session', 'recording', 'all']
def self.index(user, params = {}) def self.index(user, params = {})
limit = params[:limit] limit = params[:limit]
@ -39,9 +39,9 @@ module JamRuby
target_user = params[:user] target_user = params[:user]
target_band = params[:band] target_band = params[:band]
#query = Feed.includes([:recording]).includes([:music_session_history]).limit(limit) #query = Feed.includes([:recording]).includes([:music_session]).limit(limit)
query = Feed.joins("LEFT OUTER JOIN recordings ON recordings.id = feeds.recording_id") query = Feed.joins("LEFT OUTER JOIN recordings ON recordings.id = feeds.recording_id")
.joins("LEFT OUTER JOIN music_sessions_history ON music_sessions_history.id = feeds.music_session_id") .joins("LEFT OUTER JOIN music_sessions ON music_sessions.id = feeds.music_session_id")
.limit(limit) .limit(limit)
# handle sort # handle sort
@ -50,10 +50,10 @@ module JamRuby
query = query.order('feeds.id DESC') query = query.order('feeds.id DESC')
elsif sort == 'plays' elsif sort == 'plays'
query = query.offset(start) query = query.offset(start)
query = query.order("COALESCE(recordings.play_count, music_sessions_history.play_count) DESC ") query = query.order("COALESCE(recordings.play_count, music_sessions.play_count) DESC ")
elsif sort == 'likes' elsif sort == 'likes'
query = query.offset(start) query = query.offset(start)
query = query.order("COALESCE(recordings.like_count, music_sessions_history.like_count) DESC ") query = query.order("COALESCE(recordings.like_count, music_sessions.like_count) DESC ")
else else
raise "sort not implemented: #{sort}" raise "sort not implemented: #{sort}"
end end
@ -65,7 +65,7 @@ module JamRuby
end end
# handle type filters # handle type filters
if type_filter == 'music_session_history' if type_filter == 'music_session'
query = query.where('feeds.music_session_id is not NULL') query = query.where('feeds.music_session_id is not NULL')
elsif type_filter == 'recording' elsif type_filter == 'recording'
query = query.where('feeds.recording_id is not NULL') query = query.where('feeds.recording_id is not NULL')
@ -76,48 +76,48 @@ module JamRuby
if target_user != user.id if target_user != user.id
require_public_recordings = "claimed_recordings.is_public = TRUE AND" require_public_recordings = "claimed_recordings.is_public = TRUE AND"
require_public_sessions = "music_sessions_history.fan_access = TRUE AND" require_public_sessions = "music_sessions.fan_access = TRUE AND"
end end
query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND #{require_public_recordings} (claimed_recordings.user_id = '#{target_user}' OR (recordings.band_id IN (SELECT band_id FROM bands_musicians where user_id='#{target_user}')))") query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND #{require_public_recordings} (claimed_recordings.user_id = '#{target_user}' OR (recordings.band_id IN (SELECT band_id FROM bands_musicians where user_id='#{target_user}')))")
query = query.joins("LEFT OUTER JOIN music_sessions_user_history ON music_sessions_history.id = music_sessions_user_history.music_session_id AND #{require_public_sessions} music_sessions_user_history.user_id = '#{target_user}'") query = query.joins("LEFT OUTER JOIN music_sessions_user_history ON music_sessions.id = music_sessions_user_history.music_session_id AND #{require_public_sessions} music_sessions_user_history.user_id = '#{target_user}'")
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions_history.id") query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions.id")
if sort == 'plays' if sort == 'plays'
query = query.group("COALESCE(recordings.play_count, music_sessions_history.play_count)") query = query.group("COALESCE(recordings.play_count, music_sessions.play_count)")
elsif sort == 'likes' elsif sort == 'likes'
query = query.group("COALESCE(recordings.like_count, music_sessions_history.like_count)") query = query.group("COALESCE(recordings.like_count, music_sessions.like_count)")
end end
query = query.where('recordings.id is NULL OR claimed_recordings.id IS NOT NULL') query = query.where('recordings.id is NULL OR claimed_recordings.id IS NOT NULL')
query = query.where('music_sessions_history.id is NULL OR music_sessions_user_history.id IS NOT NULL') query = query.where('music_sessions.id is NULL OR music_sessions_user_history.id IS NOT NULL')
elsif target_band elsif target_band
unless Band.find(target_band).users.include?(user) unless Band.find(target_band).users.include?(user)
require_public_recordings = "claimed_recordings.is_public = TRUE AND" require_public_recordings = "claimed_recordings.is_public = TRUE AND"
require_public_sessions = "music_sessions_history.fan_access = TRUE AND" require_public_sessions = "music_sessions.fan_access = TRUE AND"
end end
query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND #{require_public_recordings} recordings.band_id = '#{target_band}'") query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND #{require_public_recordings} recordings.band_id = '#{target_band}'")
query = query.where("music_sessions_history IS NULL OR #{require_public_sessions} music_sessions_history.band_id = '#{target_band}'") query = query.where("music_sessions IS NULL OR #{require_public_sessions} music_sessions.band_id = '#{target_band}'")
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions_history.id") query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions.id")
if sort == 'plays' if sort == 'plays'
query = query.group("COALESCE(recordings.play_count, music_sessions_history.play_count)") query = query.group("COALESCE(recordings.play_count, music_sessions.play_count)")
elsif sort == 'likes' elsif sort == 'likes'
query = query.group("COALESCE(recordings.like_count, music_sessions_history.like_count)") query = query.group("COALESCE(recordings.like_count, music_sessions.like_count)")
end end
query = query.where('recordings.id is NULL OR claimed_recordings.id IS NOT NULL') query = query.where('recordings.id is NULL OR claimed_recordings.id IS NOT NULL')
#query = query.where('music_sessions_history.id is NULL OR music_sessions_user_history.id IS NOT NULL') #query = query.where('music_sessions.id is NULL OR music_sessions_user_history.id IS NOT NULL')
else else
query = query.joins('LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND claimed_recordings.is_public = TRUE') query = query.joins('LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND claimed_recordings.is_public = TRUE')
query = query.joins("LEFT OUTER JOIN music_sessions_user_history ON music_sessions_history.id = music_sessions_user_history.music_session_id AND music_sessions_history.fan_access = TRUE") query = query.joins("LEFT OUTER JOIN music_sessions_user_history ON music_sessions.id = music_sessions_user_history.music_session_id AND music_sessions.fan_access = TRUE")
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions_history.id") query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions.id")
if sort == 'plays' if sort == 'plays'
query = query.group("COALESCE(recordings.play_count, music_sessions_history.play_count)") query = query.group("COALESCE(recordings.play_count, music_sessions.play_count)")
elsif sort == 'likes' elsif sort == 'likes'
query = query.group("COALESCE(recordings.like_count, music_sessions_history.like_count)") query = query.group("COALESCE(recordings.like_count, music_sessions.like_count)")
end end
query = query.where('recordings.id is NULL OR claimed_recordings.is_public = TRUE') query = query.where('recordings.id is NULL OR claimed_recordings.is_public = TRUE')
query = query.where('music_sessions_history.id is NULL OR music_sessions_user_history.id IS NOT NULL') query = query.where('music_sessions.id is NULL OR music_sessions_user_history.id IS NOT NULL')
end end

View File

@ -34,7 +34,7 @@ module JamRuby
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
friend_request = FriendRequest.find(id) friend_request = FriendRequest.find(id)
friend_request.status = status friend_request.status = status
friend_request.updated_at = Time.now.getutc friend_request.updated_at = Time.now
friend_request.save friend_request.save
# create both records for this friendship # create both records for this friendship

View File

@ -7,11 +7,13 @@ module JamRuby
has_many :band_genres, class_name: "JamRuby::BandGenre" has_many :band_genres, class_name: "JamRuby::BandGenre"
has_many :bands, class_name: "JamRuby::Band", :through => :band_genres has_many :bands, class_name: "JamRuby::Band", :through => :band_genres
# music sessions
has_many :music_sessions, :class_name => "JamRuby::MusicSession"
# genres # genres
has_and_belongs_to_many :recordings, :class_name => "JamRuby::Recording", :join_table => "recordings_genres" has_and_belongs_to_many :recordings, :class_name => "JamRuby::Recording", :join_table => "recordings_genres"
# music sessions
has_and_belongs_to_many :music_sessions, :class_name => "JamRuby::MusicSession", :join_table => "genres_music_sessions"
def to_s def to_s
description description

View File

@ -11,7 +11,7 @@ module JamRuby
:sourced_needs_changing_at, as: :admin :sourced_needs_changing_at, as: :admin
belongs_to :authentication, class_name: "JamRuby::IcecastUserAuthentication", inverse_of: :mount, :foreign_key => 'authentication_id' belongs_to :authentication, class_name: "JamRuby::IcecastUserAuthentication", inverse_of: :mount, :foreign_key => 'authentication_id'
belongs_to :music_session, class_name: "JamRuby::MusicSession", inverse_of: :mount, foreign_key: 'music_session_id' belongs_to :music_session, class_name: "JamRuby::ActiveMusicSession", inverse_of: :mount, foreign_key: 'music_session_id'
belongs_to :server, class_name: "JamRuby::IcecastServer", inverse_of: :mounts, foreign_key: 'icecast_server_id' belongs_to :server, class_name: "JamRuby::IcecastServer", inverse_of: :mounts, foreign_key: 'icecast_server_id'
belongs_to :mount_template, class_name: "JamRuby::IcecastMountTemplate", inverse_of: :mounts, foreign_key: 'icecast_mount_template_id' belongs_to :mount_template, class_name: "JamRuby::IcecastMountTemplate", inverse_of: :mounts, foreign_key: 'icecast_mount_template_id'
@ -76,7 +76,7 @@ module JamRuby
end end
# creates a templated # creates a templated
def self.build_session_mount(music_session, icecast_server) def self.build_session_mount(music_session, active_music_session, icecast_server)
# only public sessions get mounts currently # only public sessions get mounts currently
return nil unless music_session.fan_access return nil unless music_session.fan_access
@ -84,7 +84,7 @@ module JamRuby
mount = nil mount = nil
if icecast_server && icecast_server.mount_template_id if icecast_server && icecast_server.mount_template_id
# we have a server with an associated mount_template; we can create a mount automatically # we have a server with an associated mount_template; we can create a mount automatically
mount = icecast_server.mount_template.build_session_mount(music_session) mount = icecast_server.mount_template.build_session_mount(music_session, active_music_session)
mount.server = icecast_server mount.server = icecast_server
end end
mount mount

View File

@ -44,7 +44,7 @@ module JamRuby
end end
# pick a server that's in the same group as the user that is under the least load # pick a server that's in the same group as the user that is under the least load
def build_session_mount(music_session) def build_session_mount(music_session, active_music_session)
mount = IcecastMount.new mount = IcecastMount.new
mount.authentication = authentication mount.authentication = authentication
mount.mount_template = self mount.mount_template = self
@ -55,7 +55,7 @@ module JamRuby
mount.stream_name = "JamKazam music session created by #{music_session.creator.name}" mount.stream_name = "JamKazam music session created by #{music_session.creator.name}"
mount.stream_description = music_session.description mount.stream_description = music_session.description
mount.stream_url = "http://www.jamkazam.com" ## TODO/XXX, the jamkazam url should be the page hosting the widget mount.stream_url = "http://www.jamkazam.com" ## TODO/XXX, the jamkazam url should be the page hosting the widget
mount.genre = music_session.genres.map {|genre| genre.description}.join(',') mount.genre = music_session.genre.description
mount mount
end end
end end

View File

@ -41,7 +41,7 @@ module JamRuby
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :inverse_of => :instrument has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :inverse_of => :instrument
# music sessions # music sessions
has_and_belongs_to_many :music_sessions, :class_name => "JamRuby::MusicSession", :join_table => "genres_music_sessions" has_and_belongs_to_many :music_sessions, :class_name => "JamRuby::ActiveMusicSession", :join_table => "genres_music_sessions"
def self.standard_list def self.standard_list
return Instrument.where('instruments.popularity > 0').order('instruments.popularity DESC, instruments.description ASC') return Instrument.where('instruments.popularity > 0').order('instruments.popularity DESC, instruments.description ASC')

View File

@ -8,7 +8,7 @@ module JamRuby
self.primary_key = 'id' self.primary_key = 'id'
belongs_to :sender, :inverse_of => :sent_invitations, :class_name => "JamRuby::User", :foreign_key => "sender_id" belongs_to :sender, :inverse_of => :sent_invitations, :class_name => "JamRuby::User", :foreign_key => "sender_id"
belongs_to :receiver, :inverse_of => :received_invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id" belongs_to :receiver, :inverse_of => :received_invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id"
belongs_to :music_session, :inverse_of => :invitations, :class_name => "JamRuby::MusicSession" belongs_to :music_session, :inverse_of => :invitations, :class_name => "JamRuby::MusicSession", :foreign_key => "music_session_id"
belongs_to :join_request, :inverse_of => :invitations, :class_name => "JamRuby::JoinRequest" belongs_to :join_request, :inverse_of => :invitations, :class_name => "JamRuby::JoinRequest"
validates :sender, :presence => true validates :sender, :presence => true
@ -20,7 +20,7 @@ module JamRuby
private private
def require_sender_in_music_session def require_sender_in_music_session
unless music_session.users.exists? sender unless music_session.part_of_session? sender
errors.add(:music_session, MEMBERSHIP_REQUIRED_OF_MUSIC_SESSION) errors.add(:music_session, MEMBERSHIP_REQUIRED_OF_MUSIC_SESSION)
end end
end end

View File

@ -6,7 +6,7 @@ module JamRuby
self.primary_key = 'id' self.primary_key = 'id'
belongs_to :user, :class_name => "JamRuby::User" belongs_to :user, :class_name => "JamRuby::User"
belongs_to :music_session, :class_name => "JamRuby::MusicSession" belongs_to :music_session, :class_name => "JamRuby::MusicSession", :foreign_key => "music_session_id"
has_many :invitations, :inverse_of => :join_request, :class_name => "JamRuby::Invitation" has_many :invitations, :inverse_of => :join_request, :class_name => "JamRuby::Invitation"
validates :user, :presence => true validates :user, :presence => true

View File

@ -1,39 +1,32 @@
module JamRuby module JamRuby
class MusicSession < ActiveRecord::Base class MusicSession < ActiveRecord::Base
attr_accessor :legal_terms
self.table_name = "music_sessions"
self.primary_key = 'id' self.primary_key = 'id'
attr_accessor :legal_terms, :skip_genre_validation, :max_score belongs_to :creator,:class_name => 'JamRuby::User', :foreign_key => :user_id, :inverse_of => :music_session_histories
attr_accessible :creator, :description, :musician_access, :approval_required, :fan_chat, :fan_access, :genres
belongs_to :creator, :inverse_of => :music_sessions, :class_name => "JamRuby::User", :foreign_key => "user_id" belongs_to :band, :class_name => 'JamRuby::Band', :foreign_key => :band_id, :inverse_of => :music_sessions
belongs_to :claimed_recording, :class_name => "JamRuby::ClaimedRecording", :foreign_key => "claimed_recording_id", :inverse_of => :playing_sessions
belongs_to :claimed_recording_initiator, :class_name => "JamRuby::User", :inverse_of => :playing_claimed_recordings, :foreign_key => "claimed_recording_initiator_id"
has_one :music_session_history, :class_name => "JamRuby::MusicSessionHistory" belongs_to :active_music_session, :class_name => 'JamRuby::ActiveMusicSession', foreign_key: :music_session_id
has_one :mount, :class_name => "JamRuby::IcecastMount", :inverse_of => :music_session, :foreign_key => 'music_session_id'
has_many :connections, :class_name => "JamRuby::Connection" has_many :music_session_user_histories, :class_name => "JamRuby::MusicSessionUserHistory", :foreign_key => "music_session_id", :dependent => :delete_all
has_many :users, :through => :connections, :class_name => "JamRuby::User" has_many :comments, :class_name => "JamRuby::MusicSessionComment", :foreign_key => "music_session_id"
has_and_belongs_to_many :genres, :class_name => "::JamRuby::Genre", :join_table => "genres_music_sessions" has_many :likes, :class_name => "JamRuby::MusicSessionLiker", :foreign_key => "session_id"
has_many :join_requests, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::JoinRequest" has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy
has_many :invitations, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::Invitation" has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id'
has_one :feed, :class_name => "JamRuby::Feed", :inverse_of => :music_session, :foreign_key => 'music_session_id', :dependent => :destroy
belongs_to :genre, :class_name => "JamRuby::Genre", :inverse_of => :music_sessions, :foreign_key => 'genre_id'
has_many :join_requests, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::JoinRequest", :foreign_key => "music_session_id"
has_many :invitations, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::Invitation", :foreign_key => "music_session_id"
has_many :invited_musicians, :through => :invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id", :source => :receiver has_many :invited_musicians, :through => :invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id", :source => :receiver
has_many :fan_invitations, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::FanInvitation", :foreign_key => "music_session_id"
has_many :fan_invitations, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::FanInvitation"
has_many :invited_fans, :through => :fan_invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id", :source => :receiver has_many :invited_fans, :through => :fan_invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id", :source => :receiver
has_many :recordings, :class_name => "JamRuby::Recording", :inverse_of => :music_session
has_many :chats, :class_name => "JamRuby::ChatMessages", :foreign_key => "session_id"
belongs_to :band, :inverse_of => :music_sessions, :class_name => "JamRuby::Band", :foreign_key => "band_id"
after_create :started_session
validate :require_at_least_one_genre, :limit_max_genres
after_save :sync_music_session_history
after_destroy do |obj|
JamRuby::MusicSessionHistory.removed_music_session(obj.id)
end
validates :genre, :presence => true
validates :description, :presence => true, :no_profanity => true validates :description, :presence => true, :no_profanity => true
validates :fan_chat, :inclusion => {:in => [true, false]} validates :fan_chat, :inclusion => {:in => [true, false]}
validates :fan_access, :inclusion => {:in => [true, false]} validates :fan_access, :inclusion => {:in => [true, false]}
@ -42,400 +35,184 @@ module JamRuby
validates :legal_terms, :inclusion => {:in => [true]}, :on => :create validates :legal_terms, :inclusion => {:in => [true]}, :on => :create
validates :creator, :presence => true validates :creator, :presence => true
validate :creator_is_musician validate :creator_is_musician
validate :no_new_playback_while_playing
#default_scope :select => "*, 0 as score" before_create :generate_share_token
before_create :add_to_feed
def attributes SHARE_TOKEN_LENGTH = 8
super.merge('max_score' => self.max_score)
SEPARATOR = '|'
def add_to_feed
feed = Feed.new
feed.music_session = self
end end
def max_score def comment_count
nil unless has_attribute?(:max_score) self.comments.size
read_attribute(:max_score).to_i
end end
before_create :create_uuid def grouped_tracks
def create_uuid tracks = []
#self.id = SecureRandom.uuid self.music_session_user_histories.each do |msuh|
end user = User.find(msuh.user_id)
t = Track.new
def before_destroy t.musician = user
self.mount.destroy if self.mount t.instrument_ids = []
end # this treats each track as a "user", which has 1 or more instruments in the session
unless msuh.instruments.blank?
def creator_is_musician instruments = msuh.instruments.split(SEPARATOR)
unless creator.musician? instruments.each do |instrument|
errors.add(:creator, ValidationMessages::MUST_BE_A_MUSICIAN) if !t.instrument_ids.include? instrument
end t.instrument_ids << instrument
end end
def no_new_playback_while_playing
# if we previous had a claimed recording and are trying to set one
# and if also the previous initiator is different than the current one... it's a no go
if !claimed_recording_id_was.nil? && !claimed_recording_id.nil? &&
claimed_recording_initiator_id_was != claimed_recording_initiator_id
errors.add(:claimed_recording, ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS)
end
end
# returns an array of client_id's that are in this session
# if as_musician is nil, all connections in the session ,regardless if it's a musician or not or not
# you can also exclude a client_id from the returned set by setting exclude_client_id
def get_connection_ids(options = {})
as_musician = options[:as_musician]
exclude_client_id = options[:exclude_client_id]
where = { :music_session_id => self.id }
where[:as_musician] = as_musician unless as_musician.nil?
exclude = "client_id != '#{exclude_client_id}'"unless exclude_client_id.nil?
Connection.select(:client_id).where(where).where(exclude).map(&:client_id)
end
# This is a little confusing. You can specify *BOTH* friends_only and my_bands_only to be true
# If so, then it's an OR condition. If both are false, you can get sessions with anyone.
def self.index(current_user, options = {})
participants = options[:participants]
genres = options[:genres]
keyword = options[:keyword]
friends_only = options[:friends_only].nil? ? false : options[:friends_only]
my_bands_only = options[:my_bands_only].nil? ? false : options[:my_bands_only]
as_musician = options[:as_musician].nil? ? true : options[:as_musician]
query = MusicSession
.joins(
%Q{
INNER JOIN
connections
ON
music_sessions.id = connections.music_session_id
}
)
.joins(
%Q{
LEFT OUTER JOIN
friendships
ON
connections.user_id = friendships.user_id
AND
friendships.friend_id = '#{current_user.id}'
}
)
.joins(
%Q{
LEFT OUTER JOIN
invitations
ON
invitations.music_session_id = music_sessions.id
AND
invitations.receiver_id = '#{current_user.id}'
}
)
.group(
%Q{
music_sessions.id
}
)
.order(
%Q{
SUM(CASE WHEN invitations.id IS NULL THEN 0 ELSE 1 END) DESC,
SUM(CASE WHEN friendships.user_id IS NULL THEN 0 ELSE 1 END) DESC,
music_sessions.created_at DESC
}
)
if as_musician
query = query.where(
%Q{
musician_access = true
OR
invitations.id IS NOT NULL
}
)
else
# if you are trying to join the session as a fan/listener,
# we have to have a mount, fan_access has to be true, and we have to allow for the reload of icecast to have taken effect
query = query.joins('INNER JOIN icecast_mounts ON icecast_mounts.music_session_id = music_sessions.id INNER JOIN icecast_servers ON icecast_mounts.icecast_server_id = icecast_servers.id')
query = query.where(:fan_access => true)
query = query.where("(music_sessions.created_at < icecast_servers.config_updated_at)")
end
query = query.where("music_sessions.description like '%#{keyword}%'") unless keyword.nil?
query = query.where("connections.user_id" => participants.split(',')) unless participants.nil?
query = query.joins(:genres).where("genres.id" => genres.split(',')) unless genres.nil?
if my_bands_only
query = query.joins(
%Q{
LEFT OUTER JOIN
bands_musicians
ON
bands_musicians.user_id = '#{current_user.id}'
}
)
end
if my_bands_only || friends_only
query = query.where(
%Q{
#{friends_only ? "friendships.user_id IS NOT NULL" : "false"}
OR
#{my_bands_only ? "bands_musicians.band_id = music_sessions.band_id" : "false"}
}
)
end
return query
end
# This is a little confusing. You can specify *BOTH* friends_only and my_bands_only to be true
# If so, then it's an OR condition. If both are false, you can get sessions with anyone.
# note, this is mostly the same as above but includes paging through the result and and scores.
# thus it needs the client_id...
def self.nindex(current_user, options = {})
client_id = options[:client_id]
participants = options[:participants]
genres = options[:genres]
keyword = options[:keyword]
friends_only = options[:friends_only].nil? ? false : options[:friends_only]
my_bands_only = options[:my_bands_only].nil? ? false : options[:my_bands_only]
as_musician = options[:as_musician].nil? ? true : options[:as_musician]
offset = options[:offset]
limit = options[:limit]
connection = Connection.where(client_id: client_id).first!
locidispid = connection.locidispid
query = MusicSession
.select("music_sessions.*, max(coalesce(current_scores.score, 1000)) as max_score") # 1000 is higher than the allowed max of 999
.joins(
%Q{
INNER JOIN
connections
ON
music_sessions.id = connections.music_session_id
}
)
.joins(
%Q{
LEFT OUTER JOIN
current_scores
ON
current_scores.alocidispid = connections.locidispid
AND
current_scores.blocidispid = #{locidispid}
}
)
.joins(
%Q{
LEFT OUTER JOIN
friendships
ON
connections.user_id = friendships.user_id
AND
friendships.friend_id = '#{current_user.id}'
}
)
.joins(
%Q{
LEFT OUTER JOIN
invitations
ON
invitations.music_session_id = music_sessions.id
AND
invitations.receiver_id = '#{current_user.id}'
}
)
.group(
%Q{
music_sessions.id
}
)
.order(
%Q{
SUM(CASE WHEN invitations.id IS NULL THEN 0 ELSE 1 END) DESC,
SUM(CASE WHEN friendships.user_id IS NULL THEN 0 ELSE 1 END) DESC,
music_sessions.created_at DESC
}
)
if (offset)
query = query.offset(offset)
end
if (limit)
query = query.limit(limit)
end
if as_musician
query = query.where(
%Q{
musician_access = true
OR
music_sessions.user_id = '#{current_user.id}'
OR
invitations.id IS NOT NULL
}
)
else
# if you are trying to join the session as a fan/listener,
# we have to have a mount, fan_access has to be true, and we have to allow for the reload of icecast to have taken effect
query = query.joins('INNER JOIN icecast_mounts ON icecast_mounts.music_session_id = music_sessions.id INNER JOIN icecast_servers ON icecast_mounts.icecast_server_id = icecast_servers.id')
query = query.where(:fan_access => true)
query = query.where("(music_sessions.created_at < icecast_servers.config_updated_at)")
end
query = query.where("music_sessions.description like '%#{keyword}%'") unless keyword.nil?
query = query.where("connections.user_id" => participants.split(',')) unless participants.nil?
query = query.joins(:genres).where("genres.id" => genres.split(',')) unless genres.nil?
if my_bands_only
query = query.joins(
%Q{
LEFT OUTER JOIN
bands_musicians
ON
bands_musicians.user_id = '#{current_user.id}'
}
)
end
if my_bands_only || friends_only
query = query.where(
%Q{
#{friends_only ? "friendships.user_id IS NOT NULL" : "false"}
OR
#{my_bands_only ? "bands_musicians.band_id = music_sessions.band_id" : "false"}
}
)
end
return query
end
# Verifies that the specified user can join this music session
def can_join? user, as_musician
if as_musician
if !user.musician
return false # "a fan can not join a music session as a musician"
raise PermissionError, "a fan can not join a music session as a musician"
end
if self.musician_access
if self.approval_required
return self.invited_musicians.exists?(user)
else
return true
end end
else
# the creator can always join, and the invited users can join
return self.creator == user || self.invited_musicians.exists?(user)
end end
else tracks << t
# it's a fan, and the only way a fan can join is if fan_access is true end
return self.fan_access tracks
end
def self.index(current_user, user_id, band_id = nil, genre = nil)
hide_private = false
if current_user.id != user_id
hide_private = false # TODO: change to true once public flag exists
end
query = MusicSession
.joins(
%Q{
LEFT OUTER JOIN
music_sessions_user_history
ON
music_sessions.id = music_sessions_user_history.music_session_id
}
)
.where(
%Q{
music_sessions.user_id = '#{user_id}'
}
)
#query = query.where("public = false") unless !hide_private
query = query.where("music_sessions.band_id = '#{band_id}") unless band_id.nil?
query = query.where("music_sessions.genres like '%#{genre}%'") unless genre.nil?
return query
end
def unique_users
User
.joins(:music_session_user_histories)
.group("users.id")
.order("users.id")
.where(%Q{ music_sessions_user_history.music_session_id = '#{id}'})
end
# returns one user history per user, with instruments all crammed together, and with total duration
def unique_user_histories
MusicSessionUserHistory
.joins(:user)
.select("STRING_AGG(instruments, '|') AS total_instruments,
SUM(date_part('epoch', COALESCE(music_sessions_user_history.session_removed_at, music_sessions_user_history.created_at) - music_sessions_user_history.created_at)) AS total_duration,
music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url")
.group("music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url")
.order("music_sessions_user_history.user_id")
.where(%Q{ music_sessions_user_history.music_session_id = '#{id}'})
end
def duration_minutes
end_time = self.session_removed_at || Time.now
(end_time - self.created_at) / 60.0
end
def music_session_user_histories
@msuh ||= JamRuby::MusicSessionUserHistory
.where(:music_session_id => self.id)
.order('created_at DESC')
end
def comments
@comments ||= JamRuby::MusicSessionComment
.where(:music_session_id => self.id)
.order('created_at DESC')
end
def likes
@likes ||= JamRuby::MusicSessionLiker
.where(:music_session_id => self.music_session_id)
end
# these are 'users that are a part of this session'
# which means are currently in the music_session, or, rsvp'ed, or creator
def part_of_session? user
# XXX check RSVP'ed
user == self.creator || (active_music_session ? active_music_session.users.exists?(user) : false)
end
def is_over?
active_music_session.nil?
end
def has_mount?
active_music_session && active_music_session.mount
end
def recordings
Recording.where(music_session_id: self.id)
end
def end_history
self.update_attribute(:session_removed_at, Time.now)
# ensure all user histories are closed
music_session_user_histories.each do |music_session_user_history|
music_session_user_history.end_history
# then update any users that need their user progress updated
if music_session_user_history.duration_minutes > 15 && music_session_user_history.max_concurrent_connections >= 3
music_session_user_history.user.update_progression_field(:first_real_music_session_at)
end
end end
end end
# Verifies that the specified user can see this music session def self.removed_music_session(session_id)
def can_see? user hist = self
if self.musician_access || self.fan_access .where(:id => session_id)
return true .limit(1)
else .first
return self.creator == user || self.invited_musicians.exists?(user)
end hist.end_history if hist
Notification.send_session_ended(session_id)
end end
# Verifies that the specified user can delete this music session def remove_non_alpha_num(token)
def can_delete? user token.gsub(/[^0-9A-Za-z]/, '')
# the creator can delete
return self.creator == user
end
def access? user
return self.users.exists? user
end
def most_recent_recording
recordings.where(:music_session_id => self.id).order('created_at desc').limit(1).first
end
# is this music session currently recording?
def is_recording?
recordings.where(:duration => nil).count > 0
end
def is_playing_recording?
!self.claimed_recording.nil?
end
def recording
recordings.where(:duration => nil).first
end
# stops any active recording
def stop_recording
current_recording = self.recording
current_recording.stop unless current_recording.nil?
end
def claimed_recording_start(owner, claimed_recording)
self.claimed_recording = claimed_recording
self.claimed_recording_initiator = owner
self.save
end
def claimed_recording_stop
self.claimed_recording = nil
self.claimed_recording_initiator = nil
self.save
end
def to_s
description
end
def tick_track_changes
self.track_changes_counter += 1
self.save!(:validate => false)
end
def connected_participant_count
Connection.where(:music_session_id => self.id,
:aasm_state => Connection::CONNECT_STATE.to_s,
:as_musician => true)
.count
end
def started_session
GoogleAnalyticsEvent.track_session_duration(self)
GoogleAnalyticsEvent.track_band_real_session(self)
end end
private private
def require_at_least_one_genre def generate_share_token
unless skip_genre_validation
if self.genres.length < Limits::MIN_GENRES_PER_SESSION token = loop do
errors.add(:genres, ValidationMessages::SESSION_GENRE_MINIMUM_NOT_MET) token = SecureRandom.urlsafe_base64(SHARE_TOKEN_LENGTH, false)
end token = remove_non_alpha_num(token)
token.upcase!
break token unless ShareToken.exists?(token: token)
end
self.share_token = ShareToken.new
self.share_token.token = token
self.share_token.shareable_type = "session"
end
def creator_is_musician
unless creator && creator.musician?
errors.add(:creator, ValidationMessages::MUST_BE_A_MUSICIAN)
end end
end end
def limit_max_genres
unless skip_genre_validation
if self.genres.length > Limits::MAX_GENRES_PER_SESSION
errors.add(:genres, ValidationMessages::SESSION_GENRE_LIMIT_EXCEEDED)
end
end
end
def sync_music_session_history
MusicSessionHistory.save(self)
end
end end
end end

View File

@ -7,8 +7,8 @@ module JamRuby
default_scope order('created_at DESC') default_scope order('created_at DESC')
belongs_to(:music_session_history, belongs_to(:music_session,
:class_name => "JamRuby::MusicSessionHistory", :class_name => "JamRuby::MusicSession",
:foreign_key => "music_session_id") :foreign_key => "music_session_id")
belongs_to(:user, belongs_to(:user,

View File

@ -1,212 +0,0 @@
module JamRuby
class MusicSessionHistory < ActiveRecord::Base
self.table_name = "music_sessions_history"
self.primary_key = 'id'
belongs_to(:user,
:class_name => 'JamRuby::User',
:foreign_key => :user_id,
:inverse_of => :music_session_histories)
belongs_to(:band,
:class_name => 'JamRuby::Band',
:foreign_key => :band_id,
:inverse_of => :music_session_history)
belongs_to(:music_session,
:class_name => 'JamRuby::MusicSession',
:foreign_key => 'music_session_id')
has_many :music_session_user_histories, :class_name => "JamRuby::MusicSessionUserHistory", :foreign_key => "music_session_id", :dependent => :delete_all
has_many :comments, :class_name => "JamRuby::MusicSessionComment", :foreign_key => "music_session_id"
has_many :likes, :class_name => "JamRuby::MusicSessionLiker", :foreign_key => "session_id"
has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy
has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id'
has_one :feed, :class_name => "JamRuby::Feed", :inverse_of => :music_session_history, :foreign_key => 'music_session_id', :dependent => :destroy
before_create :generate_share_token
before_create :add_to_feed
SHARE_TOKEN_LENGTH = 8
SEPARATOR = '|'
def add_to_feed
feed = Feed.new
feed.music_session_history = self
end
def comment_count
self.comments.size
end
def grouped_tracks
tracks = []
self.music_session_user_histories.each do |msuh|
user = User.find(msuh.user_id)
t = Track.new
t.musician = user
t.instrument_ids = []
# this treats each track as a "user", which has 1 or more instruments in the session
unless msuh.instruments.blank?
instruments = msuh.instruments.split(SEPARATOR)
instruments.each do |instrument|
if !t.instrument_ids.include? instrument
t.instrument_ids << instrument
end
end
end
tracks << t
end
tracks
end
def self.index(current_user, user_id, band_id = nil, genre = nil)
hide_private = false
if current_user.id != user_id
hide_private = false # TODO: change to true once public flag exists
end
query = MusicSessionHistory
.joins(
%Q{
LEFT OUTER JOIN
music_sessions_user_history
ON
music_sessions_history.music_session_id = music_sessions_user_history.music_session_id
}
)
.where(
%Q{
music_sessions_history.user_id = '#{user_id}'
}
)
#query = query.where("public = false") unless !hide_private
query = query.where("music_sessions_history.band_id = '#{band_id}") unless band_id.nil?
query = query.where("music_sessions_history.genres like '%#{genre}%'") unless genre.nil?
return query
end
def unique_users
User
.joins(:music_session_user_histories)
.group("users.id")
.order("users.id")
.where(%Q{ music_sessions_user_history.music_session_id = '#{music_session_id}'})
end
# returns one user history per user, with instruments all crammed together, and with total duration
def unique_user_histories
MusicSessionUserHistory
.joins(:user)
.select("STRING_AGG(instruments, '|') AS total_instruments,
SUM(date_part('epoch', COALESCE(music_sessions_user_history.session_removed_at, music_sessions_user_history.created_at) - music_sessions_user_history.created_at)) AS total_duration,
music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url")
.group("music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url")
.order("music_sessions_user_history.user_id")
.where(%Q{ music_sessions_user_history.music_session_id = '#{music_session_id}'})
end
def duration_minutes
end_time = self.session_removed_at || Time.now
(end_time - self.created_at) / 60.0
end
def music_session_user_histories
@msuh ||= JamRuby::MusicSessionUserHistory
.where(:music_session_id => self.music_session_id)
.order('created_at DESC')
end
def comments
@comments ||= JamRuby::MusicSessionComment
.where(:music_session_id => self.music_session_id)
.order('created_at DESC')
end
def likes
@likes ||= JamRuby::MusicSessionLiker
.where(:music_session_id => self.music_session_id)
end
def self.save(music_session)
session_history = MusicSessionHistory.find_by_music_session_id(music_session.id)
if session_history.nil?
session_history = MusicSessionHistory.new
end
session_history.music_session_id = music_session.id
session_history.description = music_session.description unless music_session.description.nil?
session_history.user_id = music_session.creator.id
session_history.band_id = music_session.band.id unless music_session.band.nil?
session_history.genres = music_session.genres.map { |g| g.id }.join SEPARATOR if music_session.genres.count > 0
session_history.fan_access = music_session.fan_access
session_history.save!
end
def is_over?
music_session.nil? || !session_removed_at.nil?
end
def has_mount?
music_session && music_session.mount
end
def recordings
Recording.where(music_session_id: self.id)
end
def end_history
self.update_attribute(:session_removed_at, Time.now)
# ensure all user histories are closed
music_session_user_histories.each do |music_session_user_history|
music_session_user_history.end_history
# then update any users that need their user progress updated
if music_session_user_history.duration_minutes > 15 && music_session_user_history.max_concurrent_connections >= 3
music_session_user_history.user.update_progression_field(:first_real_music_session_at)
end
end
end
def self.removed_music_session(session_id)
hist = self
.where(:music_session_id => session_id)
.limit(1)
.first
hist.end_history if hist
Notification.send_session_ended(session_id)
end
def remove_non_alpha_num(token)
token.gsub(/[^0-9A-Za-z]/, '')
end
private
def generate_share_token
self.id = music_session.id # unify music_session.id and music_session_history.id
token = loop do
token = SecureRandom.urlsafe_base64(SHARE_TOKEN_LENGTH, false)
token = remove_non_alpha_num(token)
token.upcase!
break token unless ShareToken.exists?(token: token)
end
self.share_token = ShareToken.new
self.share_token.token = token
self.share_token.shareable_type = "session"
end
end
end

View File

@ -5,7 +5,7 @@ module JamRuby
self.primary_key = 'id' self.primary_key = 'id'
belongs_to :music_session_history, class_name:"JamRuby::MusicSessionHistory", foreign_key: "music_session_id", :counter_cache => :like_count belongs_to :music_session, class_name:"JamRuby::MusicSession", foreign_key: "music_session_id", :counter_cache => :like_count
belongs_to :user, class_name: "JamRuby::User", foreign_key: "liker_id" belongs_to :user, class_name: "JamRuby::User", foreign_key: "liker_id"

View File

@ -7,13 +7,13 @@ module JamRuby
attr_accessible :uri attr_accessible :uri
belongs_to(:music_session_history, belongs_to(:music_session,
:class_name => "JamRuby::MusicSessionHistory", :class_name => "JamRuby::MusicSession",
:foreign_key => :music_session_id) :foreign_key => :music_session_id)
# mount_uploader :uri, PerfDataUploader # mount_uploader :uri, PerfDataUploader
validates :music_session_history, :presence => true validates :music_session, :presence => true
validates :client_id, :presence => true validates :client_id, :presence => true
validates :uri, :presence => true validates :uri, :presence => true

View File

@ -6,21 +6,27 @@ module JamRuby
self.primary_key = 'id' self.primary_key = 'id'
attr_accessible :max_concurrent_connections, :session_removed_at, :rating attr_accessible :max_concurrent_connections, :session_removed_at, :rating
validates_inclusion_of :rating, :in => -1..1, :allow_nil => true
belongs_to(:user, belongs_to(:user,
:class_name => "JamRuby::User", :class_name => "JamRuby::User",
:foreign_key => "user_id", :foreign_key => "user_id",
:inverse_of => :music_session_user_histories) :inverse_of => :music_session_user_histories)
belongs_to(:music_session_history, belongs_to(:music_session,
:class_name => "MusicSessionHistory", :class_name => "MusicSession",
:foreign_key => "music_session_id") :foreign_key => "music_session_id")
validates_inclusion_of :rating, :in => 0..2, :allow_nil => true def self.latest_history(client_id)
after_save :track_user_progression self.where(:client_id => client_id)
.order('created_at DESC')
.limit(1)
.includes(:user)
.first
end
def music_session_history def music_session
@msh ||= JamRuby::MusicSessionHistory.find_by_music_session_id(self.music_session_id) @msh ||= JamRuby::MusicSession.find_by_music_session_id(self.music_session_id)
end end
def perf_data def perf_data
@ -104,10 +110,23 @@ module JamRuby
self.perf_data.try(:uri) self.perf_data.try(:uri)
end end
def track_user_progression def add_rating(rval, comment='')
if self.rating == 0 rval = rval.to_i
user.update_progression_field(:first_good_music_session_at) self.rating = rval if 0 != rval
end self.rating_comment = comment
end end
MIN_SESSION_DURATION_RATING = 60
def should_rate_session?
(2 <= music_session.unique_users.all.count &&
MIN_SESSION_DURATION_RATING < (Time.now - music_session.created_at).seconds) ||
Rails.env.development?
end
def good_rating?
0 < self.rating.to_i
end
end end
end end

View File

@ -10,7 +10,7 @@ module JamRuby
belongs_to :target_user, :class_name => "JamRuby::User", :foreign_key => "target_user_id" belongs_to :target_user, :class_name => "JamRuby::User", :foreign_key => "target_user_id"
belongs_to :source_user, :class_name => "JamRuby::User", :foreign_key => "source_user_id" belongs_to :source_user, :class_name => "JamRuby::User", :foreign_key => "source_user_id"
belongs_to :band, :class_name => "JamRuby::Band", :foreign_key => "band_id" belongs_to :band, :class_name => "JamRuby::Band", :foreign_key => "band_id"
belongs_to :session, :class_name => "JamRuby::MusicSession", :foreign_key => "session_id" belongs_to :session, :class_name => "JamRuby::ActiveMusicSession", :foreign_key => "session_id"
belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id" belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id"
validates :target_user, :presence => true validates :target_user, :presence => true

View File

@ -83,8 +83,8 @@ class JamRuby::PromoLatest < JamRuby::Promotional
attr_accessible :latest attr_accessible :latest
def music_session_history def music_session
self.latest if self.latest.is_a? MusicSessionHistory self.latest if self.latest.is_a? MusicSession
end end
def recording def recording
@ -101,7 +101,7 @@ class JamRuby::PromoLatest < JamRuby::Promotional
def update_with_params(params) def update_with_params(params)
if (latest_id = params[:latest_id]).present? if (latest_id = params[:latest_id]).present?
self.latest = Recording.where(:id => latest_id).limit(1).first || self.latest = Recording.where(:id => latest_id).limit(1).first ||
MusicSessionHistory.where(:id => latest_id).limit(1).first MusicSession.where(:id => latest_id).limit(1).first
end end
self.position = params[:position] self.position = params[:position]
self.aasm_state = params[:aasm_state] self.aasm_state = params[:aasm_state]

View File

@ -16,7 +16,7 @@ module JamRuby
belongs_to :owner, :class_name => "JamRuby::User", :inverse_of => :owned_recordings, :foreign_key => 'owner_id' belongs_to :owner, :class_name => "JamRuby::User", :inverse_of => :owned_recordings, :foreign_key => 'owner_id'
belongs_to :band, :class_name => "JamRuby::Band", :inverse_of => :recordings belongs_to :band, :class_name => "JamRuby::Band", :inverse_of => :recordings
belongs_to :music_session, :class_name => "JamRuby::MusicSession", :inverse_of => :recordings belongs_to :music_session, :class_name => "JamRuby::ActiveMusicSession", :inverse_of => :recordings, foreign_key: :music_session_id
accepts_nested_attributes_for :recorded_tracks, :mixes, :claimed_recordings, allow_destroy: true accepts_nested_attributes_for :recorded_tracks, :mixes, :claimed_recordings, allow_destroy: true

View File

@ -109,7 +109,7 @@ module JamRuby
F_SORT_OPTS = [F_SORT_RECENT, F_SORT_LENGTH, F_SORT_OLDEST] F_SORT_OPTS = [F_SORT_RECENT, F_SORT_LENGTH, F_SORT_OLDEST]
SHOW_BOTH = ['Sessions & Recordings', :all] SHOW_BOTH = ['Sessions & Recordings', :all]
SHOW_SESSIONS = ['Sessions', :music_session_history] SHOW_SESSIONS = ['Sessions', :music_session]
SHOW_RECORDINGS = ['Recordings', :recording] SHOW_RECORDINGS = ['Recordings', :recording]
SHOW_OPTS = [SHOW_BOTH, SHOW_SESSIONS, SHOW_RECORDINGS] SHOW_OPTS = [SHOW_BOTH, SHOW_SESSIONS, SHOW_RECORDINGS]
@ -300,8 +300,8 @@ module JamRuby
sel_str = 'bands.*' sel_str = 'bands.*'
case ordering = self.order_param(params) case ordering = self.order_param(params)
when :plays # FIXME: double counting? when :plays # FIXME: double counting?
sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}" sel_str = "COUNT(records)+COUNT(msh) AS play_count, #{sel_str}"
rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.band_id = bands.id") rel = rel.joins("LEFT JOIN music_sessions AS msh ON msh.band_id = bands.id")
.joins("LEFT JOIN recordings AS records ON records.band_id = bands.id") .joins("LEFT JOIN recordings AS records ON records.band_id = bands.id")
.group("bands.id") .group("bands.id")
.order("play_count DESC, bands.created_at DESC") .order("play_count DESC, bands.created_at DESC")
@ -311,7 +311,7 @@ module JamRuby
.group("bands.id") .group("bands.id")
.order("COUNT(follows) DESC, bands.created_at DESC") .order("COUNT(follows) DESC, bands.created_at DESC")
when :playing when :playing
rel = rel.joins("LEFT JOIN music_sessions_history AS msh ON msh.band_id = bands.id") rel = rel.joins("LEFT JOIN music_sessions AS msh ON msh.band_id = bands.id")
.where('msh.music_session_id IS NOT NULL AND msh.session_removed_at IS NULL') .where('msh.music_session_id IS NOT NULL AND msh.session_removed_at IS NULL')
.order("bands.created_at DESC") .order("bands.created_at DESC")
end end

View File

@ -151,7 +151,7 @@ module JamRuby
track.client_track_id = client_track_id track.client_track_id = client_track_id
end end
track.updated_at = Time.now.getutc track.updated_at = Time.now
track.save track.save
return track return track
end end

View File

@ -17,7 +17,7 @@ module JamRuby
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection, :lat, :lng attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection, :lat, :lng
# updating_password corresponds to a lost_password # updating_password corresponds to a lost_password
attr_accessor :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field attr_accessor :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field, :mods_json
belongs_to :icecast_server_group, class_name: "JamRuby::IcecastServerGroup", inverse_of: :users, foreign_key: 'icecast_server_group_id' belongs_to :icecast_server_group, class_name: "JamRuby::IcecastServerGroup", inverse_of: :users, foreign_key: 'icecast_server_group_id'
@ -43,7 +43,7 @@ module JamRuby
has_many :owned_recordings, :class_name => "JamRuby::Recording", :foreign_key => "owner_id" has_many :owned_recordings, :class_name => "JamRuby::Recording", :foreign_key => "owner_id"
has_many :recordings, :through => :claimed_recordings, :class_name => "JamRuby::Recording" has_many :recordings, :through => :claimed_recordings, :class_name => "JamRuby::Recording"
has_many :claimed_recordings, :class_name => "JamRuby::ClaimedRecording", :inverse_of => :user has_many :claimed_recordings, :class_name => "JamRuby::ClaimedRecording", :inverse_of => :user
has_many :playing_claimed_recordings, :class_name => "JamRuby::MusicSession", :inverse_of => :claimed_recording_initiator has_many :playing_claimed_recordings, :class_name => "JamRuby::ActiveMusicSession", :inverse_of => :claimed_recording_initiator
# self.id = user_id in likes table # self.id = user_id in likes table
has_many :likings, :class_name => "JamRuby::Like", :inverse_of => :user, :dependent => :destroy has_many :likings, :class_name => "JamRuby::Like", :inverse_of => :user, :dependent => :destroy
@ -71,8 +71,8 @@ module JamRuby
has_many :inverse_friends, :through => :inverse_friendships, :source => :user, :class_name => "JamRuby::User" has_many :inverse_friends, :through => :inverse_friendships, :source => :user, :class_name => "JamRuby::User"
# connections / music sessions # connections / music sessions
has_many :created_music_sessions, :foreign_key => "user_id", :inverse_of => :user, :class_name => "JamRuby::MusicSession" # sessions *created* by the user has_many :created_music_sessions, :foreign_key => "user_id", :inverse_of => :user, :class_name => "JamRuby::ActiveMusicSession" # sessions *created* by the user
has_many :music_sessions, :through => :connections, :class_name => "JamRuby::MusicSession" has_many :music_sessions, :through => :connections, :class_name => "JamRuby::ActiveMusicSession"
# invitations # invitations
has_many :received_invitations, :foreign_key => "receiver_id", :inverse_of => :receiver, :class_name => "JamRuby::Invitation" has_many :received_invitations, :foreign_key => "receiver_id", :inverse_of => :receiver, :class_name => "JamRuby::Invitation"
@ -87,7 +87,7 @@ module JamRuby
has_many :sent_band_invitations, :inverse_of => :sender, :foreign_key => "creator_id", :class_name => "JamRuby::BandInvitation" has_many :sent_band_invitations, :inverse_of => :sender, :foreign_key => "creator_id", :class_name => "JamRuby::BandInvitation"
# session history # session history
has_many :music_session_histories, :foreign_key => "user_id", :class_name => "JamRuby::MusicSessionHistory", :inverse_of => :user has_many :music_session_histories, :foreign_key => "user_id", :class_name => "JamRuby::MusicSession", :inverse_of => :user
has_many :music_session_user_histories, :foreign_key => "user_id", :class_name => "JamRuby::MusicSessionUserHistory", :inverse_of => :user has_many :music_session_user_histories, :foreign_key => "user_id", :class_name => "JamRuby::MusicSessionUserHistory", :inverse_of => :user
# saved tracks # saved tracks
@ -105,6 +105,8 @@ module JamRuby
# affiliate_partner # affiliate_partner
has_one :affiliate_partner, :class_name => "JamRuby::AffiliatePartner", :foreign_key => :partner_user_id has_one :affiliate_partner, :class_name => "JamRuby::AffiliatePartner", :foreign_key => :partner_user_id
belongs_to :affiliate_referral, :class_name => "JamRuby::AffiliatePartner", :foreign_key => :affiliate_referral_id, :counter_cache => :referral_user_count belongs_to :affiliate_referral, :class_name => "JamRuby::AffiliatePartner", :foreign_key => :affiliate_referral_id, :counter_cache => :referral_user_count
# diagnostics
has_many :diagnostics, :class_name => "JamRuby::Diagnostic"
# This causes the authenticate method to be generated (among other stuff) # This causes the authenticate method to be generated (among other stuff)
#has_secure_password #has_secure_password
@ -126,6 +128,7 @@ module JamRuby
validates :subscribe_email, :inclusion => {:in => [nil, true, false]} validates :subscribe_email, :inclusion => {:in => [nil, true, false]}
validates :musician, :inclusion => {:in => [true, false]} validates :musician, :inclusion => {:in => [true, false]}
validates :show_whats_next, :inclusion => {:in => [nil, true, false]} validates :show_whats_next, :inclusion => {:in => [nil, true, false]}
validates :mods, json: true
# custom validators # custom validators
validate :validate_musician_instruments validate :validate_musician_instruments
@ -287,12 +290,25 @@ module JamRuby
self.music_sessions.size self.music_sessions.size
end end
# mods comes back as text; so give ourselves a parsed version
def mods_json
@mods_json ||= mods ? JSON.parse(mods, symbolize_names: true) : {}
end
def heartbeat_interval_client
mods_json[:heartbeat_interval_client]
end
def connection_expire_time_client
mods_json[:connection_expire_time_client]
end
def recent_history def recent_history
recordings = Recording.where(:owner_id => self.id) recordings = Recording.where(:owner_id => self.id)
.order('created_at DESC') .order('created_at DESC')
.limit(10) .limit(10)
msh = MusicSessionHistory.where(:user_id => self.id) msh = MusicSession.where(:user_id => self.id)
.order('created_at DESC') .order('created_at DESC')
.limit(10) .limit(10)
@ -339,7 +355,7 @@ module JamRuby
end end
def session_history(user_id, band_id = nil, genre = nil) def session_history(user_id, band_id = nil, genre = nil)
return MusicSessionHistory.index(self, user_id, band_id, genre) return MusicSession.index(self, user_id, band_id, genre)
end end
def session_user_history(user_id, session_id) def session_user_history(user_id, session_id)
@ -363,7 +379,7 @@ module JamRuby
return first_name + ' ' + last_name return first_name + ' ' + last_name
end end
return id id
end end
def set_password(old_password, new_password, new_password_confirmation) def set_password(old_password, new_password, new_password_confirmation)
@ -551,7 +567,7 @@ module JamRuby
self.biography = biography self.biography = biography
end end
self.updated_at = Time.now.getutc self.updated_at = Time.now
self.save self.save
end end
@ -640,7 +656,7 @@ module JamRuby
end end
# def create_session_like(targetSessionId) # def create_session_like(targetSessionId)
# targetSession = MusicSessionHistory.find(targetSessionId) # targetSession = MusicSession.find(targetSessionId)
# like = Like.new # like = Like.new
# like.likable = targetSession # like.likable = targetSession
@ -688,15 +704,7 @@ module JamRuby
unless user.nil? unless user.nil?
# only save genre id and description # only save genre id and description
genres = [] genres = [{id: music_session.genre.id, description: music_session.genre.description}]
unless music_session.genres.nil?
music_session.genres.each do |genre|
g = Hash.new
g["id"] = genre.id
g["description"] = genre.description
genres << g
end
end
# only save invitation receiver id and name # only save invitation receiver id and name
invitees = [] invitees = []

View File

@ -25,7 +25,7 @@ module JamRuby
def self.perform(args={}) def self.perform(args={})
session_id, interval_idx = args['session_id'], args['interval_idx'].to_i session_id, interval_idx = args['session_id'], args['interval_idx'].to_i
return unless session_id && session = MusicSession.find(session_id) return unless session_id && session = MusicSession.find_by_id(session_id)
GoogleAnalyticsEvent.enqueue(CAT_SESS_DUR, ACTION_SESS_DUR, SESSION_INTERVALS[interval_idx]) GoogleAnalyticsEvent.enqueue(CAT_SESS_DUR, ACTION_SESS_DUR, SESSION_INTERVALS[interval_idx])
interval_idx += 1 interval_idx += 1
@ -47,7 +47,7 @@ module JamRuby
@queue = QUEUE_BAND_TRACKER @queue = QUEUE_BAND_TRACKER
def self.perform(session_id) def self.perform(session_id)
return unless session = MusicSession.find(session_id) return unless session = ActiveMusicSession.find(session_id)
band = session.band band = session.band
if band.in_real_session?(session) if band.in_real_session?(session)
band.update_attribute(:did_real_session, true) band.update_attribute(:did_real_session, true)

View File

@ -31,46 +31,66 @@ FactoryGirl.define do
factory :single_user_session do factory :single_user_session do
after(:create) do |user, evaluator| after(:create) do |user, evaluator|
music_session = FactoryGirl.create(:music_session, :creator => user) active_music_session = FactoryGirl.create(:active_music_session, :creator => user)
connection = FactoryGirl.create(:connection, :user => user, :music_session => music_session) connection = FactoryGirl.create(:connection, :user => user, :music_session => active_music_session)
end end
end end
end end
factory :music_session_no_history, :class => JamRuby::MusicSession do factory :musician_instrument, :class => JamRuby::MusicianInstrument do
sequence(:description) { |n| "Music Session #{n}" } instrument { JamRuby::Instrument.find('electric guitar') }
proficiency_level 1
priority 0
end
factory :active_music_session_no_user_history, :class => JamRuby::ActiveMusicSession do
association :creator, factory: :user
ignore do
name "My Music Session"
description "Come Music Session"
fan_chat true
fan_access true
approval_required false
musician_access true
legal_terms true
genre JamRuby::Genre.first
band nil
end
before(:create) do |session, evaluator|
music_session = FactoryGirl.create(:music_session, name: evaluator.name, description: evaluator.description, fan_chat: evaluator.fan_chat,
fan_access: evaluator.fan_access, approval_required: evaluator.approval_required, musician_access: evaluator.musician_access,
genre: evaluator.genre, creator: evaluator.creator, band: evaluator.band)
session.id = music_session.id
end
factory :active_music_session do
after(:create) { |session|
FactoryGirl.create(:music_session_user_history, :history => session.music_session, :user => session.creator)
}
factory :active_music_session_with_mount do
association :mount, :factory => :icecast_mount
end
end
end
factory :music_session, :class => JamRuby::MusicSession do
sequence(:name) { |n| "Music Session #{n}" }
sequence(:description) { |n| "Music Session Description #{n}" }
fan_chat true fan_chat true
fan_access true fan_access true
approval_required false approval_required false
musician_access true musician_access true
legal_terms true legal_terms true
genres [JamRuby::Genre.first] language 'english'
legal_policy 'standard'
genre JamRuby::Genre.first
association :creator, :factory => :user association :creator, :factory => :user
factory :music_session do
after(:create) { |session|
FactoryGirl.create(:music_session_user_history, :history => session.music_session_history, :user => session.creator)
}
factory :music_session_with_mount do
association :mount, :factory => :icecast_mount
end
end
end
factory :music_session_history, :class => JamRuby::MusicSessionHistory do
ignore do
music_session nil
end
fan_access true
music_session_id { music_session.id }
description { music_session.description }
user_id { music_session.user_id }
band_id { music_session.band_id }
end end
factory :music_session_user_history, :class => JamRuby::MusicSessionUserHistory do factory :music_session_user_history, :class => JamRuby::MusicSessionUserHistory do
@ -80,7 +100,7 @@ FactoryGirl.define do
end end
instruments 'guitar' instruments 'guitar'
music_session_id { history.music_session_id } music_session_id { history.id }
user_id { user.id } user_id { user.id }
sequence(:client_id) { |n| "Connection #{n}" } sequence(:client_id) { |n| "Connection #{n}" }
end end
@ -154,7 +174,7 @@ FactoryGirl.define do
factory :recording, :class => JamRuby::Recording do factory :recording, :class => JamRuby::Recording do
association :owner, factory: :user association :owner, factory: :user
association :music_session, factory: :music_session association :music_session, factory: :active_music_session
association :band, factory: :band association :band, factory: :band
factory :recording_with_track do factory :recording_with_track do
@ -196,12 +216,6 @@ FactoryGirl.define do
} }
end end
factory :musician_instrument, :class => JamRuby::MusicianInstrument do
instrument { Instrument.find('electric guitar') }
proficiency_level 1
priority 0
end
factory :invited_user, :class => JamRuby::InvitedUser do factory :invited_user, :class => JamRuby::InvitedUser do
sequence(:email) { |n| "user#{n}@someservice.com" } sequence(:email) { |n| "user#{n}@someservice.com" }
autofriend false autofriend false
@ -305,7 +319,7 @@ FactoryGirl.define do
association :mount_template, :factory => :icecast_mount_template association :mount_template, :factory => :icecast_mount_template
factory :iceast_mount_with_music_session do factory :iceast_mount_with_music_session do
association :music_session, :factory => :music_session association :music_session, :factory => :active_music_session
end end
end end
end end
@ -438,4 +452,10 @@ FactoryGirl.define do
message Faker::Lorem.characters(10) message Faker::Lorem.characters(10)
end end
end end
factory :diagnostic, :class => JamRuby::Diagnostic do
type JamRuby::Diagnostic::NO_HEARTBEAT_ACK
creator JamRuby::Diagnostic::CLIENT
data Faker::Lorem.sentence
end
end end

View File

@ -4,6 +4,10 @@ require 'spec_helper'
describe ConnectionManager do describe ConnectionManager do
TRACKS = [{"instrument_id" => "electric guitar", "sound" => "mono", "client_track_id" => "some_client_track_id"}] TRACKS = [{"instrument_id" => "electric guitar", "sound" => "mono", "client_track_id" => "some_client_track_id"}]
STALE_TIME = 40
EXPIRE_TIME = 60
STALE_BUT_NOT_EXPIRED = 50
DEFINITELY_EXPIRED = 70
before do before do
@conn = PG::Connection.new(:dbname => SpecDb::TEST_DB_NAME, :user => "postgres", :password => "postgres", :host => "localhost") @conn = PG::Connection.new(:dbname => SpecDb::TEST_DB_NAME, :user => "postgres", :password => "postgres", :host => "localhost")
@ -17,17 +21,6 @@ describe ConnectionManager do
end end
end end
def create_music_session(user_id, options={})
default_options = {:musician_access => true, :fan_chat => true, :fan_access => true, :approval_required=> false}
options = default_options.merge(options)
description = "some session"
@conn.exec("INSERT INTO music_sessions (user_id, description, musician_access, approval_required, fan_chat, fan_access) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id", [user_id, description, options[:musician_access], options[:approval_required], options[:fan_chat], options[:fan_access]]) do |result|
session_id = result.getvalue(0, 0)
@conn.exec("INSERT INTO music_sessions_history (music_session_id, description, user_id, fan_access) VALUES ($1, $2, $3, $4)", [session_id, description, user_id, true])
return session_id
end
end
def assert_num_connections(client_id, expected_num_connections) def assert_num_connections(client_id, expected_num_connections)
# make sure the connection is still there # make sure the connection is still there
@conn.exec("SELECT count(*) FROM connections where client_id = $1", [client_id]) do |result| @conn.exec("SELECT count(*) FROM connections where client_id = $1", [client_id]) do |result|
@ -36,7 +29,7 @@ describe ConnectionManager do
end end
def assert_session_exists(music_session_id, exists) def assert_session_exists(music_session_id, exists)
@conn.exec("SELECT count(*) FROM music_sessions where id = $1", [music_session_id]) do |result| @conn.exec("SELECT count(*) FROM active_music_sessions where id = $1", [music_session_id]) do |result|
if exists if exists
result.getvalue(0, 0).should == "1" result.getvalue(0, 0).should == "1"
else else
@ -53,8 +46,8 @@ describe ConnectionManager do
user.save! user.save!
user = nil user = nil
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
expect { @connman.create_connection(user_id, client_id, "1.1.1.1", 'client') }.to raise_error(PG::Error) expect { @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME) }.to raise_error(PG::Error)
end end
it "create connection then delete it" do it "create connection then delete it" do
@ -63,7 +56,7 @@ describe ConnectionManager do
#user_id = create_user("test", "user2", "user2@jamkazam.com") #user_id = create_user("test", "user2", "user2@jamkazam.com")
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
count = @connman.create_connection(user.id, client_id, "1.1.1.1", 'client') count = @connman.create_connection(user.id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
count.should == 1 count.should == 1
@ -93,7 +86,7 @@ describe ConnectionManager do
#user_id = create_user("test", "user2", "user2@jamkazam.com") #user_id = create_user("test", "user2", "user2@jamkazam.com")
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
count = @connman.create_connection(user.id, client_id, "1.1.1.1", 'client') count = @connman.create_connection(user.id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
count.should == 1 count.should == 1
@ -109,7 +102,7 @@ describe ConnectionManager do
cc.addr.should == 0x01010101 cc.addr.should == 0x01010101
cc.locidispid.should == 17192000002 cc.locidispid.should == 17192000002
@connman.reconnect(cc, nil, "33.1.2.3") @connman.reconnect(cc, nil, "33.1.2.3", STALE_TIME, EXPIRE_TIME)
cc = Connection.find_by_client_id!(client_id) cc = Connection.find_by_client_id!(client_id)
cc.connected?.should be_true cc.connected?.should be_true
@ -222,20 +215,21 @@ describe ConnectionManager do
it "flag stale connection" do it "flag stale connection" do
client_id = "client_id8" client_id = "client_id8"
user_id = create_user("test", "user8", "user8@jamkazam.com") user_id = create_user("test", "user8", "user8@jamkazam.com")
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
num = JamRuby::Connection.count(:conditions => ['aasm_state = ?','connected']) num = JamRuby::Connection.count(:conditions => ['aasm_state = ?','connected'])
num.should == 1 num.should == 1
assert_num_connections(client_id, num) assert_num_connections(client_id, num)
@connman.flag_stale_connections(60) @connman.flag_stale_connections()
assert_num_connections(client_id, num) assert_num_connections(client_id, num)
sleep(1) conn = Connection.find_by_client_id(client_id)
set_updated_at(conn, Time.now - STALE_BUT_NOT_EXPIRED)
num = JamRuby::Connection.count(:conditions => ["updated_at < (NOW() - interval '#{1} second') AND aasm_state = 'connected'"]) num = JamRuby::Connection.count(:conditions => ["updated_at < (NOW() - interval '#{1} second') AND aasm_state = 'connected'"])
num.should == 1 num.should == 1
# this should change the aasm_state to stale # this should change the aasm_state to stale
@connman.flag_stale_connections(1) @connman.flag_stale_connections()
num = JamRuby::Connection.count(:conditions => ["updated_at < (NOW() - interval '#{1} second') AND aasm_state = 'connected'"]) num = JamRuby::Connection.count(:conditions => ["updated_at < (NOW() - interval '#{1} second') AND aasm_state = 'connected'"])
num.should == 0 num.should == 0
@ -244,31 +238,39 @@ describe ConnectionManager do
num.should == 1 num.should == 1
assert_num_connections(client_id, 1) assert_num_connections(client_id, 1)
cids = @connman.stale_connection_client_ids(1) conn = Connection.find_by_client_id(client_id)
cids.size.should == 1 set_updated_at(conn, Time.now - DEFINITELY_EXPIRED)
cids[0].should == client_id
cids.each { |cid| @connman.delete_connection(cid) } cids = @connman.stale_connection_client_ids()
cids.size.should == 1
cids[0][:client_id].should == client_id
cids[0][:client_type].should == Connection::TYPE_CLIENT
cids[0][:music_session_id].should be_nil
cids[0][:user_id].should == user_id
cids.each { |cid| @connman.delete_connection(cid[:client_id]) }
sleep(1)
assert_num_connections(client_id, 0) assert_num_connections(client_id, 0)
end end
it "expires stale connection" do it "expires stale connection" do
client_id = "client_id8" client_id = "client_id8"
user_id = create_user("test", "user8", "user8@jamkazam.com") user_id = create_user("test", "user8", "user8@jamkazam.com")
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
sleep(1) conn = Connection.find_by_client_id(client_id)
@connman.flag_stale_connections(1) set_updated_at(conn, Time.now - STALE_BUT_NOT_EXPIRED)
@connman.flag_stale_connections
assert_num_connections(client_id, 1) assert_num_connections(client_id, 1)
# assert_num_connections(client_id, JamRuby::Connection.count(:conditions => ['aasm_state = ?','stale'])) # assert_num_connections(client_id, JamRuby::Connection.count(:conditions => ['aasm_state = ?','stale']))
@connman.expire_stale_connections(60) @connman.expire_stale_connections
assert_num_connections(client_id, 1) assert_num_connections(client_id, 1)
sleep(1) set_updated_at(conn, Time.now - DEFINITELY_EXPIRED)
# this should delete the stale connection # this should delete the stale connection
@connman.expire_stale_connections(1) @connman.expire_stale_connections
assert_num_connections(client_id, 0) assert_num_connections(client_id, 0)
end end
@ -276,12 +278,11 @@ describe ConnectionManager do
client_id = "client_id9" client_id = "client_id9"
user_id = create_user("test", "user9", "user9@jamkazam.com") user_id = create_user("test", "user9", "user9@jamkazam.com")
music_session_id = create_music_session(user_id) music_session = FactoryGirl.create(:active_music_session, user_id: user_id)
music_session_id = music_session.id
user = User.find(user_id) user = User.find(user_id)
music_session = MusicSession.find(music_session_id)
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
connection = @connman.join_music_session(user, client_id, music_session, true, TRACKS) connection = @connman.join_music_session(user, client_id, music_session, true, TRACKS)
connection.errors.any?.should be_false connection.errors.any?.should be_false
@ -302,10 +303,10 @@ describe ConnectionManager do
client_id = "client_id10" client_id = "client_id10"
user_id = create_user("test", "user10", "user10@jamkazam.com") user_id = create_user("test", "user10", "user10@jamkazam.com")
music_session_id = create_music_session(user_id) music_session = FactoryGirl.create(:active_music_session, user_id: user_id)
music_session_id = music_session.id
user = User.find(user_id) user = User.find(user_id)
music_session = MusicSession.find(music_session_id)
expect { @connman.join_music_session(user, client_id, music_session, true, TRACKS) }.to raise_error(ActiveRecord::RecordNotFound) expect { @connman.join_music_session(user, client_id, music_session, true, TRACKS) }.to raise_error(ActiveRecord::RecordNotFound)
@ -317,13 +318,12 @@ describe ConnectionManager do
client_id2 = "client_id10.12" client_id2 = "client_id10.12"
user_id = create_user("test", "user10.11", "user10.11@jamkazam.com", :musician => true) user_id = create_user("test", "user10.11", "user10.11@jamkazam.com", :musician => true)
user_id2 = create_user("test", "user10.12", "user10.12@jamkazam.com", :musician => false) user_id2 = create_user("test", "user10.12", "user10.12@jamkazam.com", :musician => false)
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
@connman.create_connection(user_id2, client_id2, "1.1.1.1", 'client') @connman.create_connection(user_id2, client_id2, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
music_session_id = create_music_session(user_id)
music_session = FactoryGirl.create(:active_music_session, user_id: user_id)
music_session_id = music_session.id
user = User.find(user_id) user = User.find(user_id)
music_session = MusicSession.find(music_session_id)
@connman.join_music_session(user, client_id, music_session, true, TRACKS) @connman.join_music_session(user, client_id, music_session, true, TRACKS)
@ -336,13 +336,12 @@ describe ConnectionManager do
it "as_musician is coerced to boolean" do it "as_musician is coerced to boolean" do
client_id = "client_id10.2" client_id = "client_id10.2"
user_id = create_user("test", "user10.2", "user10.2@jamkazam.com", :musician => false)
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client')
music_session_id = create_music_session(user_id) user_id = create_user("test", "user10.2", "user10.2@jamkazam.com")
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
music_session = FactoryGirl.create(:active_music_session, user_id: user_id)
user = User.find(user_id) user = User.find(user_id)
music_session = MusicSession.find(music_session_id)
connection = @connman.join_music_session(user, client_id, music_session, 'blarg', TRACKS) connection = @connman.join_music_session(user, client_id, music_session, 'blarg', TRACKS)
connection.errors.size.should == 0 connection.errors.size.should == 0
@ -355,13 +354,13 @@ describe ConnectionManager do
fan_client_id = "client_id10.4" fan_client_id = "client_id10.4"
musician_id = create_user("test", "user10.3", "user10.3@jamkazam.com") musician_id = create_user("test", "user10.3", "user10.3@jamkazam.com")
fan_id = create_user("test", "user10.4", "user10.4@jamkazam.com", :musician => false) fan_id = create_user("test", "user10.4", "user10.4@jamkazam.com", :musician => false)
@connman.create_connection(musician_id, musician_client_id, "1.1.1.1", 'client') @connman.create_connection(musician_id, musician_client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
@connman.create_connection(fan_id, fan_client_id, "1.1.1.1", 'client') @connman.create_connection(fan_id, fan_client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
music_session_id = create_music_session(musician_id, :fan_access => false) music_session = FactoryGirl.create(:active_music_session, :fan_access => false, user_id: musician_id)
music_session_id = music_session.id
user = User.find(musician_id) user = User.find(musician_id)
music_session = MusicSession.find(music_session_id)
@connman.join_music_session(user, musician_client_id, music_session, true, TRACKS) @connman.join_music_session(user, musician_client_id, music_session, true, TRACKS)
@ -376,12 +375,11 @@ describe ConnectionManager do
client_id = "client_id20" client_id = "client_id20"
user_id = create_user("test", "user20", "user20@jamkazam.com") user_id = create_user("test", "user20", "user20@jamkazam.com")
user_id2 = create_user("test", "user21", "user21@jamkazam.com") user_id2 = create_user("test", "user21", "user21@jamkazam.com")
music_session_id = create_music_session(user_id) music_session = FactoryGirl.create(:active_music_session, user_id: user_id)
music_session_id = music_session.id
user = User.find(user_id2) user = User.find(user_id2)
music_session = MusicSession.find(music_session_id)
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
# specify real user id, but not associated with this session # specify real user id, but not associated with this session
expect { @connman.join_music_session(user, client_id, music_session, true, TRACKS) } .to raise_error(ActiveRecord::RecordNotFound) expect { @connman.join_music_session(user, client_id, music_session, true, TRACKS) } .to raise_error(ActiveRecord::RecordNotFound)
end end
@ -391,9 +389,9 @@ describe ConnectionManager do
user_id = create_user("test", "user11", "user11@jamkazam.com") user_id = create_user("test", "user11", "user11@jamkazam.com")
user = User.find(user_id) user = User.find(user_id)
music_session = MusicSession.new music_session = ActiveMusicSession.new
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
connection = @connman.join_music_session(user, client_id, music_session, true, TRACKS) connection = @connman.join_music_session(user, client_id, music_session, true, TRACKS)
connection.errors.size.should == 1 connection.errors.size.should == 1
connection.errors.get(:music_session).should == [ValidationMessages::MUSIC_SESSION_MUST_BE_SPECIFIED] connection.errors.get(:music_session).should == [ValidationMessages::MUSIC_SESSION_MUST_BE_SPECIFIED]
@ -403,12 +401,11 @@ describe ConnectionManager do
client_id = "client_id11.1" client_id = "client_id11.1"
user_id = create_user("test", "user11.1", "user11.1@jamkazam.com") user_id = create_user("test", "user11.1", "user11.1@jamkazam.com")
user_id2 = create_user("test", "user11.2", "user11.2@jamkazam.com") user_id2 = create_user("test", "user11.2", "user11.2@jamkazam.com")
music_session_id = create_music_session(user_id, :approval_required => true) music_session = FactoryGirl.create(:active_music_session, :approval_required => true, user_id: user_id)
music_session_id = music_session.id
user = User.find(user_id2) user = User.find(user_id2)
music_session = MusicSession.find(music_session_id)
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
# specify real user id, but not associated with this session # specify real user id, but not associated with this session
expect { @connman.join_music_session(user, client_id, music_session, true, TRACKS) } .to raise_error(ActiveRecord::RecordNotFound) expect { @connman.join_music_session(user, client_id, music_session, true, TRACKS) } .to raise_error(ActiveRecord::RecordNotFound)
end end
@ -420,9 +417,9 @@ describe ConnectionManager do
user_id = create_user("test", "user12", "user12@jamkazam.com") user_id = create_user("test", "user12", "user12@jamkazam.com")
user = User.find(user_id) user = User.find(user_id)
dummy_music_session = MusicSession.new dummy_music_session = ActiveMusicSession.new
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
expect { @connman.leave_music_session(user, Connection.find_by_client_id(client_id), dummy_music_session) }.to raise_error(JamRuby::StateError) expect { @connman.leave_music_session(user, Connection.find_by_client_id(client_id), dummy_music_session) }.to raise_error(JamRuby::StateError)
end end
@ -431,14 +428,13 @@ describe ConnectionManager do
client_id = "client_id13" client_id = "client_id13"
user_id = create_user("test", "user13", "user13@jamkazam.com") user_id = create_user("test", "user13", "user13@jamkazam.com")
music_session_id = create_music_session(user_id) music_session = FactoryGirl.create(:active_music_session, user_id: user_id)
music_session_id = music_session.id
user = User.find(user_id) user = User.find(user_id)
music_session = MusicSession.find(music_session_id)
dummy_music_session = MusicSession.new dummy_music_session = ActiveMusicSession.new
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
@connman.join_music_session(user, client_id, music_session, true, TRACKS) @connman.join_music_session(user, client_id, music_session, true, TRACKS)
expect { @connman.leave_music_session(user, Connection.find_by_client_id(client_id), dummy_music_session) }.to raise_error(JamRuby::StateError) expect { @connman.leave_music_session(user, Connection.find_by_client_id(client_id), dummy_music_session) }.to raise_error(JamRuby::StateError)
end end
@ -447,12 +443,11 @@ describe ConnectionManager do
client_id = "client_id14" client_id = "client_id14"
user_id = create_user("test", "user14", "user14@jamkazam.com") user_id = create_user("test", "user14", "user14@jamkazam.com")
music_session_id = create_music_session(user_id) music_session = FactoryGirl.create(:active_music_session, user_id: user_id)
music_session_id = music_session.id
user = User.find(user_id) user = User.find(user_id)
music_session = MusicSession.find(music_session_id)
@connman.create_connection(user_id, client_id, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
@connman.join_music_session(user, client_id, music_session, true, TRACKS) @connman.join_music_session(user, client_id, music_session, true, TRACKS)
assert_session_exists(music_session_id, true) assert_session_exists(music_session_id, true)
@ -490,19 +485,17 @@ describe ConnectionManager do
# and a connection can only point to one active music_session at a time. this is a test of # and a connection can only point to one active music_session at a time. this is a test of
# the latter but we need a test of the former, too. # the latter but we need a test of the former, too.
user_id = create_user("test", "user11", "user11@jamkazam.com") user_id = create_user("test", "user11", "user11@jamkazam.com")
user = User.find(user_id) user = User.find(user_id)
client_id1 = Faker::Number.number(20) client_id1 = Faker::Number.number(20)
@connman.create_connection(user_id, client_id1, "1.1.1.1", 'client') @connman.create_connection(user_id, client_id1, "1.1.1.1", 'client', STALE_TIME, EXPIRE_TIME)
music_session1 = MusicSession.find(create_music_session(user_id)) music_session1 = FactoryGirl.create(:active_music_session, :user_id => user_id)
connection1 = @connman.join_music_session(user, client_id1, music_session1, true, TRACKS) connection1 = @connman.join_music_session(user, client_id1, music_session1, true, TRACKS)
connection1.errors.size.should == 0 connection1.errors.size.should == 0
music_session2 = MusicSession.find(create_music_session(user_id)) music_session2 = FactoryGirl.create(:active_music_session, :user_id => user_id)
connection2 = @connman.join_music_session(user, client_id1, music_session2, true, TRACKS) connection2 = @connman.join_music_session(user, client_id1, music_session2, true, TRACKS)
connection2.errors.size.should == 1 connection2.errors.size.should == 1

View File

@ -105,7 +105,7 @@ describe 'Band search' do
def make_session(band) def make_session(band)
usr = band.users[0] usr = band.users[0]
session = FactoryGirl.create(:music_session, :creator => usr, :description => "Session", :band => band) session = FactoryGirl.create(:active_music_session, :creator => usr, :description => "Session", :band => band)
FactoryGirl.create(:connection, :user => usr, :music_session => session) FactoryGirl.create(:connection, :user => usr, :music_session => session)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
session session
@ -159,7 +159,7 @@ describe 'Band search' do
it "by now playing" do it "by now playing" do
# should get 1 result with 1 active session # should get 1 result with 1 active session
session = make_session(@band3) session = make_session(@band3)
#FactoryGirl.create(:music_session_history, :music_session => session) #FactoryGirl.create(:active_music_session, :music_session => session)
results = Search.band_filter({ :orderby => 'playing' }) results = Search.band_filter({ :orderby => 'playing' })
expect(results.results.count).to be 1 expect(results.results.count).to be 1
@ -168,7 +168,7 @@ describe 'Band search' do
# should get 2 results with 2 active sessions # should get 2 results with 2 active sessions
# sort order should be created_at DESC # sort order should be created_at DESC
session = make_session(@band4) session = make_session(@band4)
#FactoryGirl.create(:music_session_history, :music_session => session) #FactoryGirl.create(:active_music_session, :music_session => session)
results = Search.band_filter({ :orderby => 'playing' }) results = Search.band_filter({ :orderby => 'playing' })
expect(results.results.count).to be 2 expect(results.results.count).to be 2
expect(results.results[0].id).to eq(@band4.id) expect(results.results[0].id).to eq(@band4.id)

View File

@ -18,7 +18,7 @@ describe ClaimedRecording do
@connection = FactoryGirl.create(:connection, :user => @user) @connection = FactoryGirl.create(:connection, :user => @user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@music_session = FactoryGirl.create(:music_session, :creator => @user, :musician_access => true) @music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
# @music_session.connections << @connection # @music_session.connections << @connection
@music_session.save @music_session.save
@connection.join_the_session(@music_session, true, nil) @connection.join_the_session(@music_session, true, nil)

View File

@ -2,7 +2,7 @@ require 'spec_helper'
describe JamRuby::Connection do describe JamRuby::Connection do
let(:user) { FactoryGirl.create(:user) } let(:user) { FactoryGirl.create(:user) }
let (:music_session) { FactoryGirl.create(:music_session, :creator => user) } let (:music_session) { FactoryGirl.create(:active_music_session, :creator => user) }
it 'starts in the correct state' do it 'starts in the correct state' do
connection = FactoryGirl.create(:connection, connection = FactoryGirl.create(:connection,
@ -37,7 +37,7 @@ describe JamRuby::Connection do
pending 'distance search changes' pending 'distance search changes'
uu = FactoryGirl.create(:user) uu = FactoryGirl.create(:user)
uu.lat.should == nil uu.lat.should == nil
msess = FactoryGirl.create(:music_session, :creator => uu) msess = FactoryGirl.create(:active_music_session, :creator => uu)
geocode = FactoryGirl.create(:geocoder) geocode = FactoryGirl.create(:geocoder)
connection = FactoryGirl.create(:connection, connection = FactoryGirl.create(:connection,
:user => uu, :user => uu,

View File

@ -0,0 +1,18 @@
require 'spec_helper'
describe Diagnostic do
let (:user) { FactoryGirl.create(:user) }
let (:diagnostic) { FactoryGirl.create(:diagnostic, user: user) }
it 'can be made' do
diagnostic.save!
end
it "validates type" do
diagnostic = FactoryGirl.build(:diagnostic, user: user, type: 'bleh')
diagnostic.errors[:type].should == []
end
end

View File

@ -16,7 +16,7 @@ describe Feed do
it "one claimed recording" do it "one claimed recording" do
claimed_recording = FactoryGirl.create(:claimed_recording) claimed_recording = FactoryGirl.create(:claimed_recording)
MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording
MusicSessionHistory.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
feeds, start = Feed.index(user1) feeds, start = Feed.index(user1)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].recording == claimed_recording.recording feeds[0].recording == claimed_recording.recording
@ -28,7 +28,7 @@ describe Feed do
recording.recorded_tracks << second_track recording.recorded_tracks << second_track
FactoryGirl.create(:claimed_recording, recording: recording, user: second_track.user) FactoryGirl.create(:claimed_recording, recording: recording, user: second_track.user)
MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording
MusicSessionHistory.delete_all MusicSession.delete_all
# verify the mess above only made one recording # verify the mess above only made one recording
Recording.count.should == 1 Recording.count.should == 1
@ -38,16 +38,16 @@ describe Feed do
end end
it "one music session" do it "one music session" do
music_session = FactoryGirl.create(:music_session) music_session = FactoryGirl.create(:active_music_session)
feeds, start = Feed.index(user1) feeds, start = Feed.index(user1)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history == music_session.music_session_history feeds[0].music_session == music_session.music_session
end end
it "does not return a recording with no claimed recordings" do it "does not return a recording with no claimed recordings" do
recording = FactoryGirl.create(:recording) recording = FactoryGirl.create(:recording)
MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording
MusicSessionHistory.delete_all MusicSession.delete_all
feeds, start = Feed.index(user1) feeds, start = Feed.index(user1)
feeds.length.should == 0 feeds.length.should == 0
@ -60,7 +60,7 @@ describe Feed do
feeds, start = Feed.index(user1) feeds, start = Feed.index(user1)
feeds.length.should == 2 feeds.length.should == 2
feeds[0].recording.should == claimed_recording.recording feeds[0].recording.should == claimed_recording.recording
feeds[1].music_session_history.should == claimed_recording.recording.music_session.music_session_history feeds[1].music_session.should == claimed_recording.recording.music_session.music_session
end end
it "sort by plays DESC" do it "sort by plays DESC" do
@ -80,14 +80,14 @@ describe Feed do
feeds[0].recording.should == claimed_recording2.recording feeds[0].recording.should == claimed_recording2.recording
feeds[1].recording.should == claimed_recording1.recording feeds[1].recording.should == claimed_recording1.recording
FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session_history, user: user1) FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session, user: user1)
FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session_history, user: user2) FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session, user: user2)
FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session_history, user: user3) FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session, user: user3)
feeds, start = Feed.index(user1, :sort => 'plays') feeds, start = Feed.index(user1, :sort => 'plays')
feeds.length.should == 4 feeds.length.should == 4
feeds[0].music_session_history.should == claimed_recording1.recording.music_session.music_session_history feeds[0].music_session.should == claimed_recording1.recording.music_session.music_session
feeds[1].recording.should == claimed_recording2.recording feeds[1].recording.should == claimed_recording2.recording
feeds[2].recording.should == claimed_recording1.recording feeds[2].recording.should == claimed_recording1.recording
end end
@ -109,13 +109,13 @@ describe Feed do
feeds[0].recording.should == claimed_recording2.recording feeds[0].recording.should == claimed_recording2.recording
feeds[1].recording.should == claimed_recording1.recording feeds[1].recording.should == claimed_recording1.recording
FactoryGirl.create(:music_session_like, music_session_history: claimed_recording1.recording.music_session.music_session_history, user: user1) FactoryGirl.create(:music_session_like, music_session: claimed_recording1.recording.music_session.music_session, user: user1)
FactoryGirl.create(:music_session_like, music_session_history: claimed_recording1.recording.music_session.music_session_history, user: user2) FactoryGirl.create(:music_session_like, music_session: claimed_recording1.recording.music_session.music_session, user: user2)
FactoryGirl.create(:music_session_like, music_session_history: claimed_recording1.recording.music_session.music_session_history, user: user3) FactoryGirl.create(:music_session_like, music_session: claimed_recording1.recording.music_session.music_session, user: user3)
feeds, start = Feed.index(user1, :sort => 'likes') feeds, start = Feed.index(user1, :sort => 'likes')
feeds.length.should == 4 feeds.length.should == 4
feeds[0].music_session_history.should == claimed_recording1.recording.music_session.music_session_history feeds[0].music_session.should == claimed_recording1.recording.music_session.music_session
feeds[1].recording.should == claimed_recording2.recording feeds[1].recording.should == claimed_recording2.recording
feeds[2].recording.should == claimed_recording1.recording feeds[2].recording.should == claimed_recording1.recording
end end
@ -126,18 +126,18 @@ describe Feed do
# creates both recording and history record in feed # creates both recording and history record in feed
claimed_recording1 = FactoryGirl.create(:claimed_recording) claimed_recording1 = FactoryGirl.create(:claimed_recording)
feeds, start = Feed.index(user1, :type => 'music_session_history') feeds, start = Feed.index(user1, :type => 'music_session')
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history == claimed_recording1.recording.music_session.music_session_history feeds[0].music_session == claimed_recording1.recording.music_session.music_session
end end
it "returns only sessions" do it "returns only sessions" do
# creates both recording and history record in feed # creates both recording and history record in feed
claimed_recording1 = FactoryGirl.create(:claimed_recording) claimed_recording1 = FactoryGirl.create(:claimed_recording)
feeds, start = Feed.index(user1, :type => 'music_session_history') feeds, start = Feed.index(user1, :type => 'music_session')
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history == claimed_recording1.recording.music_session.music_session_history feeds[0].music_session == claimed_recording1.recording.music_session.music_session
end end
end end
@ -203,7 +203,7 @@ describe Feed do
options[:start] = start options[:start] = start
feeds, start = Feed.index(user1, options) feeds, start = Feed.index(user1, options)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == claimed_recording.recording.music_session.music_session_history feeds[0].music_session.should == claimed_recording.recording.music_session.music_session
options[:start] = start options[:start] = start
feeds, start = Feed.index(user1, options) feeds, start = Feed.index(user1, options)
@ -214,12 +214,12 @@ describe Feed do
it "supports likes pagination" do it "supports likes pagination" do
claimed_recording1 = FactoryGirl.create(:claimed_recording) claimed_recording1 = FactoryGirl.create(:claimed_recording)
FactoryGirl.create(:music_session_like, music_session_history: claimed_recording1.recording.music_session.music_session_history, user: user1) FactoryGirl.create(:music_session_like, music_session: claimed_recording1.recording.music_session.music_session, user: user1)
options = {limit: 1, sort: 'likes'} options = {limit: 1, sort: 'likes'}
feeds, start = Feed.index(user1, options) feeds, start = Feed.index(user1, options)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == claimed_recording1.recording.music_session.music_session_history feeds[0].music_session.should == claimed_recording1.recording.music_session.music_session
options[:start] = start options[:start] = start
feeds, start = Feed.index(user1, options) feeds, start = Feed.index(user1, options)
@ -235,12 +235,12 @@ describe Feed do
it "supports plays pagination" do it "supports plays pagination" do
claimed_recording1 = FactoryGirl.create(:claimed_recording) claimed_recording1 = FactoryGirl.create(:claimed_recording)
FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session_history, user: user1) FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session, user: user1)
options = {limit: 1, sort: 'plays'} options = {limit: 1, sort: 'plays'}
feeds, start = Feed.index(user1, options) feeds, start = Feed.index(user1, options)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == claimed_recording1.recording.music_session.music_session_history feeds[0].music_session.should == claimed_recording1.recording.music_session.music_session
options[:start] = start options[:start] = start
feeds, start = Feed.index(user1, options) feeds, start = Feed.index(user1, options)
@ -263,8 +263,8 @@ describe Feed do
feeds, start = Feed.index(claimed_recording1.user) feeds, start = Feed.index(claimed_recording1.user)
feeds.length.should == 1 feeds.length.should == 1
claimed_recording1.recording.music_session.fan_access = false claimed_recording1.recording.music_session.music_session.fan_access = false
claimed_recording1.recording.music_session.save! claimed_recording1.recording.music_session.music_session.save!
feeds, start = Feed.index(claimed_recording1.user) feeds, start = Feed.index(claimed_recording1.user)
feeds.length.should == 0 feeds.length.should == 0
@ -274,8 +274,8 @@ describe Feed do
describe "band feeds" do describe "band feeds" do
it "does show other band's stuff in this feed" do it "does show other band's stuff in this feed" do
other_band = FactoryGirl.create(:band) other_band = FactoryGirl.create(:band)
music_session = FactoryGirl.create(:music_session, band: other_band) music_session = FactoryGirl.create(:active_music_session, band: other_band)
FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user1) FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => user1)
claimed_recording1 = FactoryGirl.create(:claimed_recording) claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = true claimed_recording1.is_public = true
@ -290,28 +290,28 @@ describe Feed do
it "shows public recordings to you and to others" do it "shows public recordings to you and to others" do
user1.bands << band user1.bands << band
user1.save! user1.save!
music_session = FactoryGirl.create(:music_session, band: band) music_session = FactoryGirl.create(:active_music_session, band: band)
music_session.music_session_history.fan_access.should be_true music_session.music_session.fan_access.should be_true
feeds, start = Feed.index(user1, band: band.id) feeds, start = Feed.index(user1, band: band.id)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history feeds[0].music_session.should == music_session.music_session
feeds, start = Feed.index(user2, band: band.id) feeds, start = Feed.index(user2, band: band.id)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history feeds[0].music_session.should == music_session.music_session
end end
it "shows private sessions to you, not to others" do it "shows private sessions to you, not to others" do
user1.bands << band user1.bands << band
user1.save! user1.save!
music_session = FactoryGirl.create(:music_session, band: band, fan_access: false) music_session = FactoryGirl.create(:active_music_session, band: band, fan_access: false)
music_session.music_session_history.fan_access.should be_false music_session.music_session.fan_access.should be_false
feeds, start = Feed.index(user1, band: band.id) feeds, start = Feed.index(user1, band: band.id)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history feeds[0].music_session.should == music_session.music_session
feeds[0].music_session_history.fan_access.should be_false feeds[0].music_session.fan_access.should be_false
feeds, start = Feed.index(user2, band: band.id) feeds, start = Feed.index(user2, band: band.id)
@ -355,8 +355,8 @@ describe Feed do
describe "user feeds" do describe "user feeds" do
it "does not show stuff from other people" do it "does not show stuff from other people" do
music_session = FactoryGirl.create(:music_session) music_session = FactoryGirl.create(:active_music_session)
FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user2) FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => user2)
claimed_recording1 = FactoryGirl.create(:claimed_recording) claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = true claimed_recording1.is_public = true
@ -367,28 +367,28 @@ describe Feed do
end end
it "shows public sessions to you and to others" do it "shows public sessions to you and to others" do
music_session = FactoryGirl.create(:music_session) music_session = FactoryGirl.create(:active_music_session)
FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user1) FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => user1)
feeds, start = Feed.index(user1, user: user1.id) feeds, start = Feed.index(user1, user: user1.id)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history feeds[0].music_session.should == music_session.music_session
feeds, start = Feed.index(user2, user: user1.id) feeds, start = Feed.index(user2, user: user1.id)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history feeds[0].music_session.should == music_session.music_session
end end
it "shows private sessions to you, not to others" do it "shows private sessions to you, not to others" do
music_session = FactoryGirl.create(:music_session, fan_access: false) music_session = FactoryGirl.create(:active_music_session, fan_access: false)
music_session.music_session_history.fan_access.should be_false music_session.music_session.fan_access.should be_false
FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user1) FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => user1)
feeds, start = Feed.index(user1, user: user1.id) feeds, start = Feed.index(user1, user: user1.id)
feeds.length.should == 1 feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history feeds[0].music_session.should == music_session.music_session
feeds[0].music_session_history.fan_access.should be_false feeds[0].music_session.fan_access.should be_false
feeds, start = Feed.index(user2, user: user1.id) feeds, start = Feed.index(user2, user: user1.id)

View File

@ -166,39 +166,39 @@ describe IcecastMount do
let(:server1) {FactoryGirl.create(:icecast_server_minimal)} let(:server1) {FactoryGirl.create(:icecast_server_minimal)}
let(:server2) {FactoryGirl.create(:icecast_server_with_overrides)} let(:server2) {FactoryGirl.create(:icecast_server_with_overrides)}
let(:server3) {FactoryGirl.create(:icecast_server_with_overrides)} let(:server3) {FactoryGirl.create(:icecast_server_with_overrides)}
let(:hidden_music_session) { FactoryGirl.create(:music_session, :fan_access => false)} let(:hidden_music_session) { FactoryGirl.create(:active_music_session, :fan_access => false)}
let(:public_music_session) { FactoryGirl.create(:music_session, :fan_access => true)} let(:public_music_session) { FactoryGirl.create(:active_music_session, :fan_access => true)}
let(:public_music_session2) { FactoryGirl.create(:music_session, :fan_access => true)} let(:public_music_session2) { FactoryGirl.create(:active_music_session, :fan_access => true)}
let(:public_music_session3) { FactoryGirl.create(:music_session, :fan_access => true)} let(:public_music_session3) { FactoryGirl.create(:active_music_session, :fan_access => true)}
before(:each) do before(:each) do
end end
it "no fan access means no mount" do it "no fan access means no mount" do
mount = IcecastMount.build_session_mount(hidden_music_session, IcecastServer.find_best_server_for_user(hidden_music_session.creator)) mount = IcecastMount.build_session_mount(hidden_music_session.music_session, hidden_music_session, IcecastServer.find_best_server_for_user(hidden_music_session.creator))
mount.should be_nil mount.should be_nil
end end
it "with no servers" do it "with no servers" do
IcecastServer.count.should == 0 IcecastServer.count.should == 0
mount = IcecastMount.build_session_mount(public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator)) mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.should be_nil mount.should be_nil
end end
it "with a server that has a mount template" do it "with a server that has a mount template" do
server1.mount_template.should_not be_nil server1.mount_template.should_not be_nil
mount = IcecastMount.build_session_mount(public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator)) mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.should_not be_nil mount.should_not be_nil
mount.save! mount.save!
end end
it "with a server that already has an associated mount" do it "with a server that already has an associated mount" do
server1.mount_template.should_not be_nil server1.mount_template.should_not be_nil
mount = IcecastMount.build_session_mount(public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator)) mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.save! mount.save!
mount = IcecastMount.build_session_mount(public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator)) mount = IcecastMount.build_session_mount(public_music_session2.music_session, public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator))
mount.save! mount.save!
server1.reload server1.reload
server1.mounts.length.should == 2 server1.mounts.length.should == 2
@ -207,13 +207,13 @@ describe IcecastMount do
it "picks a second server once the 1st has been chosen" do it "picks a second server once the 1st has been chosen" do
server1.touch server1.touch
mount = IcecastMount.build_session_mount(public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator)) mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.listeners = 1 # affect the weight mount.listeners = 1 # affect the weight
mount.save! mount.save!
server2.touch server2.touch
mount = IcecastMount.build_session_mount(public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator)) mount = IcecastMount.build_session_mount(public_music_session2.music_session, public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator))
mount.save! mount.save!
server1.reload server1.reload
server1.mounts.length.should == 1 server1.mounts.length.should == 1
@ -224,17 +224,17 @@ describe IcecastMount do
it "picks the 1st server again once the 2nd has higher weight" do it "picks the 1st server again once the 2nd has higher weight" do
server1.touch server1.touch
mount = IcecastMount.build_session_mount(public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator)) mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.listeners = 1 # affect the weight mount.listeners = 1 # affect the weight
mount.save! mount.save!
server2.touch server2.touch
mount = IcecastMount.build_session_mount(public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator)) mount = IcecastMount.build_session_mount(public_music_session2.music_session, public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator))
mount.sourced = 1 mount.sourced = 1
mount.save! mount.save!
mount = IcecastMount.build_session_mount(public_music_session3, IcecastServer.find_best_server_for_user(public_music_session3.creator)) mount = IcecastMount.build_session_mount(public_music_session3.music_session, public_music_session3, IcecastServer.find_best_server_for_user(public_music_session3.creator))
mount.listeners = 1 mount.listeners = 1
mount.save! mount.save!

View File

@ -10,11 +10,11 @@ describe IcecastMountTemplate do
describe "poke configs" do describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) } let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
let(:music_session) { FactoryGirl.create(:music_session, :fan_access => true)} let(:music_session) { FactoryGirl.create(:active_music_session, :fan_access => true)}
before(:each) do before(:each) do
server.touch server.touch
mount = IcecastMount.build_session_mount(music_session, IcecastServer.find_best_server_for_user(music_session.creator)) mount = IcecastMount.build_session_mount(music_session.music_session, music_session, IcecastServer.find_best_server_for_user(music_session.creator))
mount.save! mount.save!
server.save! server.save!
server.config_updated server.config_updated

View File

@ -1,18 +1,18 @@
require 'spec_helper' require 'spec_helper'
describe MusicSession do describe ActiveMusicSession do
it 'cant create invitation to non-friend' do it 'cant create invitation to non-friend' do
user1 = FactoryGirl.create(:user) # in the jam session user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1") music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1")
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2") music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2")
invitation = Invitation.new(:sender => user1, :receiver => user2, :music_session => music_session) invitation = Invitation.new(:sender => user1, :receiver => user2, :music_session => music_session.music_session)
invitation.save.should be_false invitation.save.should be_false
invitation.errors.size.should == 1 invitation.errors.size.should == 1
@ -24,7 +24,7 @@ describe MusicSession do
user1 = FactoryGirl.create(:user) # in the jam session user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1") music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1")
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2") music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2")
@ -32,7 +32,7 @@ describe MusicSession do
FactoryGirl.create(:friendship, :user => user1, :friend => user2) FactoryGirl.create(:friendship, :user => user1, :friend => user2)
FactoryGirl.create(:friendship, :user => user2, :friend => user1) FactoryGirl.create(:friendship, :user => user2, :friend => user1)
invitation = Invitation.new(:sender => user1, :receiver => user2, :music_session => music_session) invitation = Invitation.new(:sender => user1, :receiver => user2, :music_session => music_session.music_session)
invitation.save.should be_true invitation.save.should be_true
end end
@ -41,14 +41,14 @@ describe MusicSession do
user1 = FactoryGirl.create(:user) # in the jam session user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1") music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1")
connection2 = FactoryGirl.create(:connection, :user => user2, :ip_address => "2.2.2.2", :client_id => "2") connection2 = FactoryGirl.create(:connection, :user => user2, :ip_address => "2.2.2.2", :client_id => "2")
join_request = FactoryGirl.create(:join_request, :user => user2, :music_session => music_session) join_request = FactoryGirl.create(:join_request, :user => user2, :music_session => music_session.music_session)
invitation = Invitation.new(:sender => user1, :receiver => user2, :music_session => music_session, :join_request => join_request) invitation = Invitation.new(:sender => user1, :receiver => user2, :music_session => music_session.music_session, :join_request => join_request)
invitation.save.should be_true invitation.save.should be_true
end end
@ -57,15 +57,15 @@ describe MusicSession do
user1 = FactoryGirl.create(:user) # in the jam session user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session2 = FactoryGirl.create(:music_session, :creator => user1) music_session2 = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1") music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1")
connection2 = FactoryGirl.create(:connection, :user => user2, :ip_address => "2.2.2.2", :client_id => "2") connection2 = FactoryGirl.create(:connection, :user => user2, :ip_address => "2.2.2.2", :client_id => "2")
join_request = FactoryGirl.create(:join_request, :user => user2, :music_session => music_session2) join_request = FactoryGirl.create(:join_request, :user => user2, :music_session => music_session2.music_session)
invitation = Invitation.new(:sender => user1, :receiver => user2, :music_session => music_session, :join_request => join_request) invitation = Invitation.new(:sender => user1, :receiver => user2, :music_session => music_session.music_session, :join_request => join_request)
invitation.save.should be_false invitation.save.should be_false
invitation.errors.get(:join_request).should == [Invitation::JOIN_REQUEST_IS_NOT_FOR_RECEIVER_AND_MUSIC_SESSION ] invitation.errors.get(:join_request).should == [Invitation::JOIN_REQUEST_IS_NOT_FOR_RECEIVER_AND_MUSIC_SESSION ]

View File

@ -4,9 +4,9 @@ describe JoinRequest do
it 'can create a join request' do it 'can create a join request' do
user1 = FactoryGirl.create(:user) user1 = FactoryGirl.create(:user)
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session) music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
join_request = JoinRequest.new(:user => user1, :music_session => music_session, :text => "Let me join yo") join_request = JoinRequest.new(:user => user1, :music_session => music_session.music_session, :text => "Let me join yo")
join_request.save.should be_true join_request.save.should be_true
@ -18,9 +18,9 @@ describe JoinRequest do
it 'fans cant create a join request' do it 'fans cant create a join request' do
user1 = FactoryGirl.create(:user, :musician => true) user1 = FactoryGirl.create(:user, :musician => true)
user2 = FactoryGirl.create(:user, :musician => false) user2 = FactoryGirl.create(:user, :musician => false)
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session) music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
join_request = JoinRequest.new(:user => user2, :music_session => music_session, :text => "Let me join yo") join_request = JoinRequest.new(:user => user2, :music_session => music_session.music_session, :text => "Let me join yo")
join_request.save.should be_false join_request.save.should be_false
join_request.errors.size.should == 1 join_request.errors.size.should == 1
@ -29,12 +29,12 @@ describe JoinRequest do
it 'cant create a dup join_request' do it 'cant create a dup join_request' do
user1 = FactoryGirl.create(:user) user1 = FactoryGirl.create(:user)
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session) music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
join_request = JoinRequest.new(:user => user1, :music_session => music_session, :text => "Let me join yo") join_request = JoinRequest.new(:user => user1, :music_session => music_session.music_session, :text => "Let me join yo")
join_request.save.should be_true join_request.save.should be_true
join_request2 = JoinRequest.new(:user => user1, :music_session => music_session, :text => "Let me join yo") join_request2 = JoinRequest.new(:user => user1, :music_session => music_session.music_session, :text => "Let me join yo")
join_request2.save.should be_false join_request2.save.should be_false
join_request2.errors.get(:user_id) == ["has already been taken"] join_request2.errors.get(:user_id) == ["has already been taken"]
@ -42,9 +42,9 @@ describe JoinRequest do
it "cant contain profanity in the text" do it "cant contain profanity in the text" do
user1 = FactoryGirl.create(:user) user1 = FactoryGirl.create(:user)
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session) music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
join_request = JoinRequest.new(:user => user1, :music_session => music_session, :text => "fuck you") join_request = JoinRequest.new(:user => user1, :music_session => music_session.music_session, :text => "fuck you")
join_request.save join_request.save
join_request.valid?.should be_false join_request.valid?.should be_false
end end

View File

@ -7,7 +7,7 @@ describe Mix do
@connection = FactoryGirl.create(:connection, :user => @user) @connection = FactoryGirl.create(:connection, :user => @user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@music_session = FactoryGirl.create(:music_session, :creator => @user, :musician_access => true) @music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
# @music_session.connections << @connection # @music_session.connections << @connection
@music_session.save @music_session.save
@connection.join_the_session(@music_session, true, nil) @connection.join_the_session(@music_session, true, nil)

View File

@ -1,23 +1,57 @@
require 'spec_helper' require 'spec_helper'
describe MusicSessionHistory do describe MusicSession do
let(:creator) {FactoryGirl.create(:user)}
let(:some_user) { FactoryGirl.create(:user) } let(:some_user) { FactoryGirl.create(:user) }
let(:music_session) { FactoryGirl.create(:music_session_no_history) } let(:music_session) { FactoryGirl.create(:active_music_session_no_user_history) }
let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => music_session.creator, :created_at => 2.days.ago, :session_removed_at => 1.days.ago) } let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => music_session.creator, :created_at => 2.days.ago, :session_removed_at => 1.days.ago) }
let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => some_user, :created_at => 2.days.ago, :session_removed_at => 1.days.ago) } let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_user, :created_at => 2.days.ago, :session_removed_at => 1.days.ago) }
let(:user_history3) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => music_session.creator, :created_at => 3.days.ago, :session_removed_at => 2.days.ago) } let(:user_history3) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => music_session.creator, :created_at => 3.days.ago, :session_removed_at => 2.days.ago) }
let(:user_history4) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => some_user, :created_at => 3.days.ago, :session_removed_at => 2.days.ago) } let(:user_history4) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_user, :created_at => 3.days.ago, :session_removed_at => 2.days.ago) }
it "create" do describe "validations" do
music_session.music_session_history.description.should eql(music_session.description) it "genre must be set" do
music_session = FactoryGirl.build(:music_session)
music_session.genre = nil
music_session.save.should be_false
music_session.errors[:genre].should == ["can't be blank"]
end
it "updates the fields of a music session properly" do
genre1 = FactoryGirl.create(:genre)
genre2 = FactoryGirl.create(:genre)
genre3 = FactoryGirl.create(:genre)
genre4 = FactoryGirl.create(:genre)
creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :genre => genre3)
session.update_attributes({:description => "Session2", :genre => genre1})
session.reload
session.description.should == "Session2"
session.genre.should == genre1
end
it "must have legal_terms accepted" do
user1 = FactoryGirl.create(:user)
music_session = FactoryGirl.build(:music_session, :creator => user1, legal_terms: false)
music_session.save
music_session.valid?.should be_false
music_session.errors["legal_terms"].should == ["is not included in the list"]
end
it "cannot have profanity in the description" do
user1 = FactoryGirl.create(:user)
music_session = FactoryGirl.build(:music_session, :creator => user1, legal_terms: false, :description => "fuck you")
music_session.save
music_session.valid?.should be_false
end
end end
it "unique users" do it "unique users" do
user_history1.should_not be_nil user_history1.should_not be_nil
user_history2.should_not be_nil user_history2.should_not be_nil
users = music_session.music_session_history.unique_users users = music_session.music_session.unique_users
users.length.should eql(2) users.length.should eql(2)
@ -26,7 +60,7 @@ describe MusicSessionHistory do
user_history3.should_not be_nil user_history3.should_not be_nil
user_history4.should_not be_nil user_history4.should_not be_nil
users = music_session.music_session_history.unique_users users = music_session.music_session.unique_users
users.length.should eql(2) users.length.should eql(2)
users.include?(some_user).should be_true users.include?(some_user).should be_true
@ -44,7 +78,7 @@ describe MusicSessionHistory do
user_history2.session_removed_at = session_removed_at user_history2.session_removed_at = session_removed_at
user_history2.save! user_history2.save!
histories = music_session.music_session_history.unique_user_histories histories = music_session.music_session.unique_user_histories
histories.length.should eql(2) histories.length.should eql(2)
histories[0].first_name.should_not be_nil histories[0].first_name.should_not be_nil
histories[0].last_name.should_not be_nil histories[0].last_name.should_not be_nil
@ -62,7 +96,7 @@ describe MusicSessionHistory do
user_history4.session_removed_at = session_removed_at user_history4.session_removed_at = session_removed_at
user_history4.save! user_history4.save!
histories = music_session.music_session_history.unique_user_histories histories = music_session.music_session.unique_user_histories
histories.length.should eql(2) histories.length.should eql(2)
histories[0].total_duration.to_i.should == 2.day.to_i histories[0].total_duration.to_i.should == 2.day.to_i
histories[0].total_instruments.should == 'guitar|guitar' histories[0].total_instruments.should == 'guitar|guitar'

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe MusicSessionPerfData do describe MusicSessionPerfData do
before do before do
#music_session = FactoryGirl.create(:music_session) #music_session = FactoryGirl.create(:active_music_session)
#connection = FactoryGirl.create(:connection, :music_session => music_session) #connection = FactoryGirl.create(:connection, :music_session => music_session)
end end

View File

@ -1,28 +1,20 @@
require 'spec_helper' require 'spec_helper'
describe MusicSession do describe ActiveMusicSession do
before(:each) do before(:each) do
MusicSession.delete_all ActiveMusicSession.delete_all
IcecastServer.delete_all IcecastServer.delete_all
IcecastMount.delete_all IcecastMount.delete_all
end end
describe "validations" do
it "genre must be set" do
music_session = FactoryGirl.build(:music_session)
music_session.genres = []
music_session.save.should be_false
music_session.errors[:genres].should == [ValidationMessages::SESSION_GENRE_MINIMUM_NOT_MET]
end
end
it 'can grant access to valid user' do it 'can grant access to valid user' do
user1 = FactoryGirl.create(:user) # in the jam session user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
user3 = FactoryGirl.create(:user) # not in the jam session user3 = FactoryGirl.create(:user) # not in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1, :musician_access => false) music_session = FactoryGirl.create(:active_music_session, :creator => user1, :musician_access => false)
FactoryGirl.create(:connection, :user => user1, :music_session => music_session) FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
FactoryGirl.create(:connection, :user => user2, :music_session => music_session) FactoryGirl.create(:connection, :user => user2, :music_session => music_session)
@ -38,7 +30,7 @@ describe MusicSession do
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
user3 = FactoryGirl.create(:user) # not in the jam session user3 = FactoryGirl.create(:user) # not in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1, :musician_access => true) music_session = FactoryGirl.create(:active_music_session, :creator => user1, :musician_access => true)
music_session.can_join?(user1, true).should == true music_session.can_join?(user1, true).should == true
music_session.can_join?(user2, true).should == true music_session.can_join?(user2, true).should == true
@ -50,7 +42,7 @@ describe MusicSession do
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
user3 = FactoryGirl.create(:user) # not in the jam session user3 = FactoryGirl.create(:user) # not in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1, :musician_access => false) music_session = FactoryGirl.create(:active_music_session, :creator => user1, :musician_access => false)
FactoryGirl.create(:connection, :user => user1, :music_session => music_session) FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
music_session.can_join?(user1, true).should == true music_session.can_join?(user1, true).should == true
@ -60,7 +52,7 @@ describe MusicSession do
# invite user 2 # invite user 2
FactoryGirl.create(:friendship, :user => user1, :friend => user2) FactoryGirl.create(:friendship, :user => user1, :friend => user2)
FactoryGirl.create(:friendship, :user => user2, :friend => user1) FactoryGirl.create(:friendship, :user => user2, :friend => user1)
FactoryGirl.create(:invitation, :sender => user1, :receiver => user2, :music_session => music_session) FactoryGirl.create(:invitation, :sender => user1, :receiver => user2, :music_session => music_session.music_session)
music_session.can_join?(user1, true).should == true music_session.can_join?(user1, true).should == true
music_session.can_join?(user2, true).should == true music_session.can_join?(user2, true).should == true
@ -72,7 +64,7 @@ describe MusicSession do
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
user3 = FactoryGirl.create(:user) # not in the jam session user3 = FactoryGirl.create(:user) # not in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1, :musician_access => false, :fan_access => false) music_session = FactoryGirl.create(:active_music_session, :creator => user1, :musician_access => false, :fan_access => false)
FactoryGirl.create(:connection, :user => user1, :music_session => music_session) FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
music_session.can_see?(user1).should == true music_session.can_see?(user1).should == true
@ -82,29 +74,28 @@ describe MusicSession do
# invite user 2 # invite user 2
FactoryGirl.create(:friendship, :user => user1, :friend => user2) FactoryGirl.create(:friendship, :user => user1, :friend => user2)
FactoryGirl.create(:friendship, :user => user2, :friend => user1) FactoryGirl.create(:friendship, :user => user2, :friend => user1)
FactoryGirl.create(:invitation, :sender => user1, :receiver => user2, :music_session => music_session) FactoryGirl.create(:invitation, :sender => user1, :receiver => user2, :music_session => music_session.music_session)
music_session.can_see?(user1).should == true music_session.can_see?(user1).should == true
music_session.can_see?(user2).should == true music_session.can_see?(user2).should == true
music_session.can_see?(user3).should == false music_session.can_see?(user3).should == false
end end
describe "index" do describe "index" do
it "orders two sessions by created_at starting with most recent" do it "orders two sessions by created_at starting with most recent" do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
creator2 = FactoryGirl.create(:user) creator2 = FactoryGirl.create(:user)
earlier_session = FactoryGirl.create(:music_session, :creator => creator, :description => "Earlier Session") earlier_session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Earlier Session")
FactoryGirl.create(:connection, :user => creator, :music_session => earlier_session) FactoryGirl.create(:connection, :user => creator, :music_session => earlier_session)
later_session = FactoryGirl.create(:music_session, :creator => creator2, :description => "Later Session") later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session")
FactoryGirl.create(:connection, :user => creator2, :music_session => later_session) FactoryGirl.create(:connection, :user => creator2, :music_session => later_session)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
#ActiveRecord::Base.logger = Logger.new(STDOUT) #ActiveRecord::Base.logger = Logger.new(STDOUT)
music_sessions = MusicSession.index(user) music_sessions = ActiveMusicSession.index(user)
music_sessions.length.should == 2 music_sessions.length.should == 2
music_sessions.first.id.should == later_session.id music_sessions.first.id.should == later_session.id
end end
@ -113,17 +104,17 @@ describe MusicSession do
creator1 = FactoryGirl.create(:user) creator1 = FactoryGirl.create(:user)
creator2 = FactoryGirl.create(:user) creator2 = FactoryGirl.create(:user)
earlier_session = FactoryGirl.create(:music_session, :creator => creator1, :description => "Earlier Session") earlier_session = FactoryGirl.create(:active_music_session, :creator => creator1, :description => "Earlier Session")
FactoryGirl.create(:connection, :user => creator1, :music_session => earlier_session) FactoryGirl.create(:connection, :user => creator1, :music_session => earlier_session)
later_session = FactoryGirl.create(:music_session, :creator => creator2, :description => "Later Session") later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session")
FactoryGirl.create(:connection, :user => creator2, :music_session => later_session) FactoryGirl.create(:connection, :user => creator2, :music_session => later_session)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
FactoryGirl.create(:connection, :user => creator1, :music_session => earlier_session) FactoryGirl.create(:connection, :user => creator1, :music_session => earlier_session)
FactoryGirl.create(:friendship, :user => creator1, :friend => user) FactoryGirl.create(:friendship, :user => creator1, :friend => user)
FactoryGirl.create(:friendship, :user => user, :friend => creator1) FactoryGirl.create(:friendship, :user => user, :friend => creator1)
FactoryGirl.create(:invitation, :sender => creator1, :receiver => user, :music_session => earlier_session) FactoryGirl.create(:invitation, :sender => creator1, :receiver => user, :music_session => earlier_session.music_session)
music_sessions = MusicSession.index(user) music_sessions = ActiveMusicSession.index(user)
music_sessions.length.should == 2 music_sessions.length.should == 2
music_sessions.first.id.should == earlier_session.id music_sessions.first.id.should == earlier_session.id
end end
@ -133,9 +124,9 @@ describe MusicSession do
creator1 = FactoryGirl.create(:user) creator1 = FactoryGirl.create(:user)
creator2 = FactoryGirl.create(:user) creator2 = FactoryGirl.create(:user)
earlier_session = FactoryGirl.create(:music_session, :creator => creator1, :description => "Earlier Session") earlier_session = FactoryGirl.create(:active_music_session, :creator => creator1, :description => "Earlier Session")
FactoryGirl.create(:connection, :user => creator1, :music_session => earlier_session) FactoryGirl.create(:connection, :user => creator1, :music_session => earlier_session)
later_session = FactoryGirl.create(:music_session, :creator => creator2, :description => "Later Session") later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session")
FactoryGirl.create(:connection, :user => creator2, :music_session => later_session) FactoryGirl.create(:connection, :user => creator2, :music_session => later_session)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
@ -144,41 +135,41 @@ describe MusicSession do
FactoryGirl.create(:connection, :user => creator1, :music_session => earlier_session) FactoryGirl.create(:connection, :user => creator1, :music_session => earlier_session)
FactoryGirl.create(:connection, :user => creator2, :music_session => earlier_session) FactoryGirl.create(:connection, :user => creator2, :music_session => earlier_session)
music_sessions = MusicSession.index(user) music_sessions = ActiveMusicSession.index(user)
music_sessions.length.should == 2 music_sessions.length.should == 2
music_sessions.first.id.should == earlier_session.id music_sessions.first.id.should == earlier_session.id
end end
it "doesn't list a session if musician_access is set to false" do it "doesn't list a session if musician_access is set to false" do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :musician_access => false) session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session", :musician_access => false)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
music_sessions = MusicSession.index(user) music_sessions = ActiveMusicSession.index(user)
music_sessions.length.should == 0 music_sessions.length.should == 0
end end
it "does list a session if musician_access is set to false but user was invited" do it "does list a session if musician_access is set to false but user was invited" do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :musician_access => false) session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session", :musician_access => false)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
FactoryGirl.create(:connection, :user => creator, :music_session => session) FactoryGirl.create(:connection, :user => creator, :music_session => session)
FactoryGirl.create(:friendship, :user => creator, :friend => user) FactoryGirl.create(:friendship, :user => creator, :friend => user)
FactoryGirl.create(:friendship, :user => user, :friend => creator) FactoryGirl.create(:friendship, :user => user, :friend => creator)
FactoryGirl.create(:invitation, :sender => creator, :receiver => user, :music_session => session) FactoryGirl.create(:invitation, :sender => creator, :receiver => user, :music_session => session.music_session)
music_sessions = MusicSession.index(user) music_sessions = ActiveMusicSession.index(user)
music_sessions.length.should == 1 music_sessions.length.should == 1
end end
it "lists a session if the genre matches" do it "lists a session if the genre matches" do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
genre = FactoryGirl.create(:genre) genre = FactoryGirl.create(:genre)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :genres => [genre]) session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session", :genre => genre)
FactoryGirl.create(:connection, :user => creator, :music_session => session) FactoryGirl.create(:connection, :user => creator, :music_session => session)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
music_sessions = MusicSession.index(user, genres: [genre.id]) music_sessions = ActiveMusicSession.index(user, genres: [genre.id])
music_sessions.length.should == 1 music_sessions.length.should == 1
end end
@ -186,37 +177,37 @@ describe MusicSession do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
genre1 = FactoryGirl.create(:genre) genre1 = FactoryGirl.create(:genre)
genre2 = FactoryGirl.create(:genre) genre2 = FactoryGirl.create(:genre)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :genres => [genre1]) session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session", :genre => genre1)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
music_sessions = MusicSession.index(user, genres: [genre2.id]) music_sessions = ActiveMusicSession.index(user, genres: [genre2.id])
music_sessions.length.should == 0 music_sessions.length.should == 0
end end
it "does not list a session if friends_only is set and no friends are in it" do it "does not list a session if friends_only is set and no friends are in it" do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session") session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session")
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
music_sessions = MusicSession.index(user, friends_only: true) music_sessions = ActiveMusicSession.index(user, friends_only: true)
music_sessions.length.should == 0 music_sessions.length.should == 0
end end
it "lists a session properly if a friend is in it" do it "lists a session properly if a friend is in it" do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session") session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session")
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
FactoryGirl.create(:friendship, :user => creator, :friend => user) FactoryGirl.create(:friendship, :user => creator, :friend => user)
FactoryGirl.create(:friendship, :user => user, :friend => creator) FactoryGirl.create(:friendship, :user => user, :friend => creator)
FactoryGirl.create(:connection, :user => creator, :music_session => session) FactoryGirl.create(:connection, :user => creator, :music_session => session)
music_sessions = MusicSession.index(user) music_sessions = ActiveMusicSession.index(user)
music_sessions.length.should == 1 music_sessions.length.should == 1
music_sessions = MusicSession.index(user, friends_only: true) music_sessions = ActiveMusicSession.index(user, friends_only: true)
music_sessions.length.should == 1 music_sessions.length.should == 1
music_sessions = MusicSession.index(user, friends_only: false, my_bands_only: true) music_sessions = ActiveMusicSession.index(user, friends_only: false, my_bands_only: true)
music_sessions.length.should == 0 music_sessions.length.should == 0
music_sessions = MusicSession.index(user, friends_only: true, my_bands_only: true) music_sessions = ActiveMusicSession.index(user, friends_only: true, my_bands_only: true)
music_sessions.length.should == 1 music_sessions.length.should == 1
end end
@ -225,46 +216,46 @@ describe MusicSession do
# however, this bug continually crops up so the .index method will protect against this common bug # however, this bug continually crops up so the .index method will protect against this common bug
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session") session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session")
session.connections.delete_all # should leave a bogus, 0 participant session around session.connections.delete_all # should leave a bogus, 0 participant session around
music_sessions = MusicSession.index(creator) music_sessions = ActiveMusicSession.index(creator)
music_sessions.length.should == 0 music_sessions.length.should == 0
end end
it "does not list a session if my_bands_only is set and it's not my band" do it "does not list a session if my_bands_only is set and it's not my band" do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session") session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session")
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
music_sessions = MusicSession.index(user, friends_only: false, my_bands_only: true) music_sessions = ActiveMusicSession.index(user, friends_only: false, my_bands_only: true)
music_sessions.length.should == 0 music_sessions.length.should == 0
end end
it "lists a session properly if it's my band's session" do it "lists a session properly if it's my band's session" do
band = FactoryGirl.create(:band) band = FactoryGirl.create(:band)
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :band => band) session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Session", :band => band)
FactoryGirl.create(:connection, :user => creator, :music_session => session) FactoryGirl.create(:connection, :user => creator, :music_session => session)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
FactoryGirl.create(:band_musician, :band => band, :user => creator) FactoryGirl.create(:band_musician, :band => band, :user => creator)
FactoryGirl.create(:band_musician, :band => band, :user => user) FactoryGirl.create(:band_musician, :band => band, :user => user)
music_sessions = MusicSession.index(user) music_sessions = ActiveMusicSession.index(user)
music_sessions.length.should == 1 music_sessions.length.should == 1
music_sessions = MusicSession.index(user, friends_only: true) music_sessions = ActiveMusicSession.index(user, friends_only: true)
music_sessions.length.should == 0 music_sessions.length.should == 0
music_sessions = MusicSession.index(user, friends_only: false, my_bands_only: true) music_sessions = ActiveMusicSession.index(user, friends_only: false, my_bands_only: true)
music_sessions.length.should == 1 music_sessions.length.should == 1
music_sessions = MusicSession.index(user, friends_only: true, my_bands_only: true) music_sessions = ActiveMusicSession.index(user, friends_only: true, my_bands_only: true)
music_sessions.length.should == 1 music_sessions.length.should == 1
end end
describe "index(as_musician: false)" do describe "index(as_musician: false)" do
let(:fan_access) { true } let(:fan_access) { true }
let(:creator) { FactoryGirl.create(:user) } let(:creator) { FactoryGirl.create(:user) }
let(:session) { FactoryGirl.create(:music_session, creator: creator, fan_access: fan_access ) } let(:session) { FactoryGirl.create(:active_music_session, creator: creator, fan_access: fan_access ) }
let(:connection) { FactoryGirl.create(:connection, user: creator, :music_session => session) } let(:connection) { FactoryGirl.create(:connection, user: creator, :music_session => session) }
let(:user) {FactoryGirl.create(:user) } let(:user) {FactoryGirl.create(:user) }
@ -277,13 +268,13 @@ describe MusicSession do
it "no session listed if mount is nil" do it "no session listed if mount is nil" do
connection.touch connection.touch
sessions = MusicSession.index(user, as_musician: false) sessions = ActiveMusicSession.index(user, as_musician: false)
sessions.length.should == 0 sessions.length.should == 0
end end
end end
describe "with mount" do describe "with mount" do
let(:session_with_mount) { FactoryGirl.create(:music_session_with_mount) } let(:session_with_mount) { FactoryGirl.create(:active_music_session_with_mount) }
let(:connection_with_mount) { FactoryGirl.create(:connection, user: creator, :music_session => session_with_mount) } let(:connection_with_mount) { FactoryGirl.create(:connection, user: creator, :music_session => session_with_mount) }
@ -293,7 +284,7 @@ describe MusicSession do
it "no session listed if icecast_server config hasn't been updated" do it "no session listed if icecast_server config hasn't been updated" do
connection_with_mount.touch connection_with_mount.touch
sessions = MusicSession.index(user, as_musician: false) sessions = ActiveMusicSession.index(user, as_musician: false)
sessions.length.should == 0 sessions.length.should == 0
end end
@ -303,7 +294,7 @@ describe MusicSession do
session_with_mount.save!(:validate => false) session_with_mount.save!(:validate => false)
session_with_mount.mount.server.config_updated_at = 1.minute.ago session_with_mount.mount.server.config_updated_at = 1.minute.ago
session_with_mount.mount.server.save!(:validate => false) session_with_mount.mount.server.save!(:validate => false)
sessions = MusicSession.index(user, as_musician: false) sessions = ActiveMusicSession.index(user, as_musician: false)
sessions.length.should == 1 sessions.length.should == 1
end end
end end
@ -316,10 +307,10 @@ describe MusicSession do
creator = FactoryGirl.create(:user) creator = FactoryGirl.create(:user)
creator2 = FactoryGirl.create(:user) creator2 = FactoryGirl.create(:user)
earlier_session = FactoryGirl.create(:music_session, :creator => creator, :description => "Earlier Session") earlier_session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Earlier Session")
c1 = FactoryGirl.create(:connection, user: creator, music_session: earlier_session, addr: 0x01020304, locidispid: 1) c1 = FactoryGirl.create(:connection, user: creator, music_session: earlier_session, addr: 0x01020304, locidispid: 1)
later_session = FactoryGirl.create(:music_session, :creator => creator2, :description => "Later Session") later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session")
c2 = FactoryGirl.create(:connection, user: creator2, music_session: later_session, addr: 0x21020304, locidispid: 2) c2 = FactoryGirl.create(:connection, user: creator2, music_session: later_session, addr: 0x21020304, locidispid: 2)
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
@ -331,7 +322,7 @@ describe MusicSession do
# scores! # scores!
#ActiveRecord::Base.logger = Logger.new(STDOUT) #ActiveRecord::Base.logger = Logger.new(STDOUT)
music_sessions = MusicSession.nindex(user, client_id: c3.client_id).take(100) music_sessions = ActiveMusicSession.nindex(user, client_id: c3.client_id).take(100)
#music_sessions = MusicSession.index(user).take(100) #music_sessions = MusicSession.index(user).take(100)
#ActiveRecord::Base.logger = nil #ActiveRecord::Base.logger = nil
@ -341,50 +332,22 @@ describe MusicSession do
end end
end end
it "updates the fields of a music session properly" do
genre1 = FactoryGirl.create(:genre)
genre2 = FactoryGirl.create(:genre)
genre3 = FactoryGirl.create(:genre)
genre4 = FactoryGirl.create(:genre)
creator = FactoryGirl.create(:user)
session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :genres => [genre3,genre4])
session.update_attributes({:description => "Session2", :genre => [genre1, genre2]})
session.genres = [genre1, genre2]
session.reload
session.description.should == "Session2"
session.genres.length.should == 2
session.genres[0].id.should == genre1.id
end
it 'uninvited users cant join approval-required sessions without invitation' do it 'uninvited users cant join approval-required sessions without invitation' do
user1 = FactoryGirl.create(:user) # in the jam session user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1, :musician_access => true, :approval_required => true) music_session = FactoryGirl.create(:active_music_session, :creator => user1, :musician_access => true, :approval_required => true)
connection1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session) connection1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session)
expect { FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :joining_session => true) }.to raise_error(ActiveRecord::RecordInvalid) expect { FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :joining_session => true) }.to raise_error(ActiveRecord::RecordInvalid)
end end
it "must have legal_terms accepted" do
user1 = FactoryGirl.create(:user)
music_session = FactoryGirl.build(:music_session, :creator => user1, :legal_terms=> false)
music_session.save
music_session.valid?.should be_false
music_session.errors["legal_terms"].should == ["is not included in the list"]
end
it "cannot have profanity in the description" do
user1 = FactoryGirl.create(:user)
music_session = FactoryGirl.build(:music_session, :creator => user1, :legal_terms=> false, :description => "fuck you")
music_session.save
music_session.valid?.should be_false
end
it "is_recording? returns false if not recording" do it "is_recording? returns false if not recording" do
user1 = FactoryGirl.create(:user) user1 = FactoryGirl.create(:user)
music_session = FactoryGirl.build(:music_session, :creator => user1) music_session = FactoryGirl.build(:active_music_session, :creator => user1)
music_session.is_recording?.should be_false music_session.is_recording?.should be_false
end end
@ -395,7 +358,7 @@ describe MusicSession do
@connection = FactoryGirl.create(:connection, :user => @user1) @connection = FactoryGirl.create(:connection, :user => @user1)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@music_session = FactoryGirl.create(:music_session, :creator => @user1, :musician_access => true) @music_session = FactoryGirl.create(:active_music_session, :creator => @user1, :musician_access => true)
# @music_session.connections << @connection # @music_session.connections << @connection
@music_session.save! @music_session.save!
@connection.join_the_session(@music_session, true, nil) @connection.join_the_session(@music_session, true, nil)
@ -474,7 +437,7 @@ describe MusicSession do
before(:each) do before(:each) do
@user1 = FactoryGirl.create(:user) @user1 = FactoryGirl.create(:user)
@user2 = FactoryGirl.create(:user) @user2 = FactoryGirl.create(:user)
@music_session = FactoryGirl.create(:music_session, :creator => @user1, :musician_access => true) @music_session = FactoryGirl.create(:active_music_session, :creator => @user1, :musician_access => true)
@connection1 = FactoryGirl.create(:connection, :user => @user1, :music_session => @music_session, :as_musician => true) @connection1 = FactoryGirl.create(:connection, :user => @user1, :music_session => @music_session, :as_musician => true)
@connection2 = FactoryGirl.create(:connection, :user => @user2, :music_session => @music_session, :as_musician => false) @connection2 = FactoryGirl.create(:connection, :user => @user2, :music_session => @music_session, :as_musician => false)
@ -500,14 +463,5 @@ describe MusicSession do
@music_session.get_connection_ids(exclude_client_id: @connection2.client_id, as_musician: true).should == [@connection1.client_id] @music_session.get_connection_ids(exclude_client_id: @connection2.client_id, as_musician: true).should == [@connection1.client_id]
end end
end end
describe "autosave of music session history" do
it "is created on initial music session create" do
music_session = FactoryGirl.create(:music_session)
history = MusicSessionHistory.find(music_session.id)
history.genres.should == music_session.genres.first.id
end
end
end end

View File

@ -3,11 +3,12 @@ require 'spec_helper'
describe MusicSessionUserHistory do describe MusicSessionUserHistory do
let(:some_user) { FactoryGirl.create(:user) } let(:some_user) { FactoryGirl.create(:user) }
let(:music_session) { FactoryGirl.create(:music_session_no_history) } let(:music_session) { FactoryGirl.create(:active_music_session_no_user_history) }
let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => music_session.creator) } let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => music_session.creator) }
let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => some_user) } let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_user) }
describe "create" do describe "create" do
pending
it {user_history1.music_session_id.should == music_session.id } it {user_history1.music_session_id.should == music_session.id }
it {user_history1.created_at.should_not be_nil } it {user_history1.created_at.should_not be_nil }
it {user_history1.session_removed_at.should be_nil } it {user_history1.session_removed_at.should be_nil }
@ -15,28 +16,35 @@ describe MusicSessionUserHistory do
describe "rating" do describe "rating" do
describe "success" do it "success" do
user_history1.update_attribute(:rating, 1)
before(:each) do expect( user_history1.errors.any? ).to eq(false)
user_history1.update_attribute(:rating ,0)
end
it { user_history1.errors.any?.should be_false}
end end
describe "out of range" do it "out of range" do
before(:each) do user_history1.rating = 2
user_history1.update_attribute(:rating, 3) user_history1.save
user_history1.save expect( user_history1.errors.any? ).to eq(true)
end end
it { user_history1.errors.any?.should be_true} it 'should rate success' do
users = [user_history1, user_history2]
Timecop.travel(Time.now + (MusicSessionUserHistory::MIN_SESSION_DURATION_RATING * 1.5).seconds)
expect( user_history1.should_rate_session? ).to eq(true)
Timecop.return
end
it 'should rate fails' do
users = [user_history1]
expect( user_history1.should_rate_session? ).to eq(false)
users = [user_history1, user_history2]
expect( user_history2.should_rate_session? ).to eq(false)
end end
end end
describe "end_history" do describe "end_history" do
pending
it "histories created at the same time" do it "histories created at the same time" do
user_history1.reload user_history1.reload
user_history2.reload user_history2.reload
@ -77,7 +85,7 @@ describe MusicSessionUserHistory do
end end
it "two histories with same user within bounds of history1" do it "two histories with same user within bounds of history1" do
user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => some_user) user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_user)
# if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3 # if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3
user_history1.session_removed_at = user_history1.created_at + 5 user_history1.session_removed_at = user_history1.created_at + 5
@ -98,7 +106,7 @@ describe MusicSessionUserHistory do
it "two histories with different user within bounds of history1" do it "two histories with different user within bounds of history1" do
third_user = FactoryGirl.create(:user); third_user = FactoryGirl.create(:user);
user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => third_user) user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => third_user)
# if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3 # if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3
user_history1.session_removed_at = user_history1.created_at + 5 user_history1.session_removed_at = user_history1.created_at + 5
@ -119,7 +127,7 @@ describe MusicSessionUserHistory do
it "two overlapping histories with different user within bounds of history1" do it "two overlapping histories with different user within bounds of history1" do
third_user = FactoryGirl.create(:user); third_user = FactoryGirl.create(:user);
user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => third_user) user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => third_user)
# if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3 # if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3
user_history1.session_removed_at = user_history1.created_at + 5 user_history1.session_removed_at = user_history1.created_at + 5
@ -136,10 +144,7 @@ describe MusicSessionUserHistory do
user_history1.end_history user_history1.end_history
user_history1.max_concurrent_connections.should == 3 user_history1.max_concurrent_connections.should == 3
end end
end end
end end

View File

@ -112,7 +112,7 @@ describe 'Musician search' do
connection = FactoryGirl.create(:connection, :user => usr) connection = FactoryGirl.create(:connection, :user => usr)
instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
track = FactoryGirl.create(:track, :connection => connection, :instrument => instrument) track = FactoryGirl.create(:track, :connection => connection, :instrument => instrument)
music_session = FactoryGirl.create(:music_session, :creator => usr, :musician_access => true) music_session = FactoryGirl.create(:active_music_session, :creator => usr, :musician_access => true)
# music_session.connections << connection # music_session.connections << connection
music_session.save music_session.save
connection.join_the_session(music_session, true, nil) connection.join_the_session(music_session, true, nil)
@ -127,7 +127,7 @@ describe 'Musician search' do
def make_session(usr) def make_session(usr)
connection = FactoryGirl.create(:connection, :user => usr) connection = FactoryGirl.create(:connection, :user => usr)
music_session = FactoryGirl.create(:music_session, :creator => usr, :musician_access => true) music_session = FactoryGirl.create(:active_music_session, :creator => usr, :musician_access => true)
# music_session.connections << connection # music_session.connections << connection
music_session.save music_session.save
connection.join_the_session(music_session, true, nil) connection.join_the_session(music_session, true, nil)

View File

@ -9,7 +9,7 @@ describe RecordedTrack do
@user = FactoryGirl.create(:user) @user = FactoryGirl.create(:user)
@connection = FactoryGirl.create(:connection, :user => @user) @connection = FactoryGirl.create(:connection, :user => @user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@music_session = FactoryGirl.create(:music_session, :creator => @user, :musician_access => true) @music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@recording = FactoryGirl.create(:recording, :music_session => @music_session, :owner => @user) @recording = FactoryGirl.create(:recording, :music_session => @music_session, :owner => @user)
end end

View File

@ -5,7 +5,7 @@ describe Recording do
before do before do
@user = FactoryGirl.create(:user) @user = FactoryGirl.create(:user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@music_session = FactoryGirl.create(:music_session, :creator => @user, :musician_access => true) @music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
@connection = FactoryGirl.create(:connection, :user => @user, :music_session => @music_session) @connection = FactoryGirl.create(:connection, :user => @user, :music_session => @music_session)
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
end end

View File

@ -3,7 +3,7 @@ require 'spec_helper'
describe ShareToken do describe ShareToken do
let(:user) { FactoryGirl.create(:user) } let(:user) { FactoryGirl.create(:user) }
let(:music_session) {FactoryGirl.create(:music_session) } let(:music_session) {FactoryGirl.create(:active_music_session) }
let(:claimed_recording) {FactoryGirl.create(:claimed_recording) } let(:claimed_recording) {FactoryGirl.create(:claimed_recording) }
before(:each) do before(:each) do
@ -13,9 +13,9 @@ describe ShareToken do
it "can reference a music session" do it "can reference a music session" do
music_session.touch # should create a MSH, and a token, too music_session.touch # should create a MSH, and a token, too
ShareToken.count.should == 1 ShareToken.count.should == 1
music_session.music_session_history.share_token.should_not be_nil music_session.music_session.share_token.should_not be_nil
token = ShareToken.find_by_shareable_id!(music_session.id) token = ShareToken.find_by_shareable_id!(music_session.id)
token.should == music_session.music_session_history.share_token token.should == music_session.music_session.share_token
token.shareable_id.should == music_session.id token.shareable_id.should == music_session.id
token.shareable_type.should == 'session' token.shareable_type.should == 'session'
end end

View File

@ -3,11 +3,11 @@ require 'spec_helper'
describe Track do describe Track do
let (:user) {FactoryGirl.create(:user) } let (:user) {FactoryGirl.create(:user) }
let (:music_session) { FactoryGirl.create(:music_session, :creator => user)} let (:music_session) { FactoryGirl.create(:active_music_session, :creator => user)}
let (:connection) { FactoryGirl.create(:connection, :user => user, :music_session => music_session) } let (:connection) { FactoryGirl.create(:connection, :user => user, :music_session => music_session) }
let (:track) { FactoryGirl.create(:track, :connection => connection)} let (:track) { FactoryGirl.create(:track, :connection => connection)}
let (:track2) { FactoryGirl.create(:track, :connection => connection)} let (:track2) { FactoryGirl.create(:track, :connection => connection)}
let (:msuh) {FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user, :client_id => connection.client_id) } let (:msuh) {FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => user, :client_id => connection.client_id) }
let (:track_hash) { {:client_track_id => 'client_guid', :sound => 'stereo', :instrument_id => 'drums'} } let (:track_hash) { {:client_track_id => 'client_guid', :sound => 'stereo', :instrument_id => 'drums'} }
before(:each) do before(:each) do
@ -74,14 +74,7 @@ describe Track do
it "updates a single track using .id to correlate" do it "updates a single track using .id to correlate" do
track.id.should_not be_nil track.id.should_not be_nil
connection.tracks.length.should == 1 connection.tracks.length.should == 1
begin set_updated_at(track, 1.days.ago)
ActiveRecord::Base.record_timestamps = false
track.updated_at = 1.days.ago
track.save!
ensure
# very important to turn it back; it'll break all tests otherwise
ActiveRecord::Base.record_timestamps = true
end
tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => 'client_guid_new', :sound => 'mono', :instrument_id => 'drums'}]) tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => 'client_guid_new', :sound => 'mono', :instrument_id => 'drums'}])
tracks.length.should == 1 tracks.length.should == 1
found = tracks[0] found = tracks[0]
@ -105,14 +98,7 @@ describe Track do
it "does not touch updated_at when nothing changes" do it "does not touch updated_at when nothing changes" do
track.id.should_not be_nil track.id.should_not be_nil
connection.tracks.length.should == 1 connection.tracks.length.should == 1
begin set_updated_at(track, 1.days.ago)
ActiveRecord::Base.record_timestamps = false
track.updated_at = 1.days.ago
track.save!
ensure
# very important to turn it back; it'll break all tests otherwise
ActiveRecord::Base.record_timestamps = true
end
tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => track.client_track_id, :sound => track.sound, :instrument_id => track.instrument_id}]) tracks = Track.sync(connection.client_id, [{:id => track.id, :client_track_id => track.client_track_id, :sound => track.sound, :instrument_id => track.instrument_id}])
tracks.length.should == 1 tracks.length.should == 1
found = tracks[0] found = tracks[0]

View File

@ -21,6 +21,7 @@ describe User do
it { should respond_to(:admin) } it { should respond_to(:admin) }
it { should respond_to(:valid_password?) } it { should respond_to(:valid_password?) }
it { should respond_to(:can_invite) } it { should respond_to(:can_invite) }
it { should respond_to(:mods) }
it { should be_valid } it { should be_valid }
it { should_not be_admin } it { should_not be_admin }
@ -69,6 +70,24 @@ describe User do
it { should_not be_valid } it { should_not be_valid }
end end
describe "when mods is null" do
before { @user.mods = nil }
it { should be_valid }
end
describe "when mods is empty" do
before { @user.mods = 'nil' }
it { should_not be_valid }
end
describe "when mods is json object" do
before { @user.mods = '{"key":"value"}' }
it { should be_valid }
end
describe "first or last name cant have profanity" do describe "first or last name cant have profanity" do
it "should not let the first name have profanity" do it "should not let the first name have profanity" do
@user.first_name = "fuck you" @user.first_name = "fuck you"
@ -118,6 +137,7 @@ describe User do
it "should be saved as all lower-case" do it "should be saved as all lower-case" do
pending
@user.email = mixed_case_email @user.email = mixed_case_email
@user.save! @user.save!
@user.reload.email.should == mixed_case_email.downcase @user.reload.email.should == mixed_case_email.downcase
@ -428,6 +448,29 @@ describe User do
end end
describe "mods" do
it "should allow update of JSON" do
@user.mods = {some_field: 5}.to_json
@user.save!
end
it "should return heartbeart interval" do
@user.heartbeat_interval_client.should be_nil
@user.mods = {heartbeat_interval_client: 5}.to_json
@user.save!
@user = User.find(@user.id) # necessary because mods_json is cached in the model
@user.heartbeat_interval_client.should == 5
end
it "should return connection_expire_time" do
@user.connection_expire_time_client.should be_nil
@user.mods = {connection_expire_time_client: 5}.to_json
@user.save!
@user = User.find(@user.id) # necessary because mods_json is cached in the model
@user.connection_expire_time_client.should == 5
end
end
=begin =begin
describe "update avatar" do describe "update avatar" do

View File

@ -11,7 +11,7 @@ describe MQRouter do
user1 = FactoryGirl.create(:user) # in the jam session user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1") music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1")
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2") music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2")
@ -37,7 +37,7 @@ describe MQRouter do
user1 = FactoryGirl.create(:user) # in the jam session user1 = FactoryGirl.create(:user) # in the jam session
user2 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session
music_session = FactoryGirl.create(:music_session, :creator => user1) music_session = FactoryGirl.create(:active_music_session, :creator => user1)
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1") music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :ip_address => "1.1.1.1", :client_id => "1")
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2") music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :ip_address => "2.2.2.2", :client_id => "2")

View File

@ -154,7 +154,7 @@ describe AudioMixer do
@connection = FactoryGirl.create(:connection, :user => @user) @connection = FactoryGirl.create(:connection, :user => @user)
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
@music_session = FactoryGirl.create(:music_session, :creator => @user, :musician_access => true) @music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
# @music_session.connections << @connection # @music_session.connections << @connection
@music_session.save @music_session.save
@connection.join_the_session(@music_session, true, nil) @connection.join_the_session(@music_session, true, nil)

View File

@ -13,7 +13,7 @@ describe GoogleAnalyticsEvent do
ResqueSpec.reset! ResqueSpec.reset!
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
band = FactoryGirl.create(:band) band = FactoryGirl.create(:band)
music_session = FactoryGirl.create(:music_session, music_session = FactoryGirl.create(:active_music_session,
:creator => user, :creator => user,
:musician_access => true, :musician_access => true,
:band => band) :band => band)
@ -34,7 +34,7 @@ describe GoogleAnalyticsEvent do
band.users << user band.users << user
band.users << user1 band.users << user1
band.reload band.reload
music_session = FactoryGirl.create(:music_session, :creator => user, music_session = FactoryGirl.create(:active_music_session, :creator => user,
:musician_access => true, :band => band) :musician_access => true, :band => band)
expect(band.band_musicians.count).to eq(2) expect(band.band_musicians.count).to eq(2)
expect(band.did_real_session).to eq(false) expect(band.did_real_session).to eq(false)
@ -73,7 +73,7 @@ describe GoogleAnalyticsEvent do
end end
it 'reports size increment' do it 'reports size increment' do
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
music_session = FactoryGirl.create(:music_session, music_session = FactoryGirl.create(:active_music_session,
:creator => user, :creator => user,
:musician_access => true) :musician_access => true)
connection = FactoryGirl.create(:connection, :user => user, connection = FactoryGirl.create(:connection, :user => user,
@ -88,7 +88,7 @@ describe GoogleAnalyticsEvent do
it 'reports duration' do it 'reports duration' do
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
JamRuby::GoogleAnalyticsEvent::SessionDurationTracker.should have_schedule_size_of(0) JamRuby::GoogleAnalyticsEvent::SessionDurationTracker.should have_schedule_size_of(0)
music_session = FactoryGirl.create(:music_session, music_session = FactoryGirl.create(:active_music_session,
:creator => user, :creator => user,
:musician_access => true) :musician_access => true)
GoogleAnalyticsEvent::SessionDurationTracker.should have_schedule_size_of(1) GoogleAnalyticsEvent::SessionDurationTracker.should have_schedule_size_of(1)

View File

@ -136,14 +136,7 @@ describe IcecastConfigWriter do
pending "failing on build server" pending "failing on build server"
server.touch server.touch
begin set_updated_at(server, Time.now.ago(APP_CONFIG.icecast_max_missing_check + 1))
ActiveRecord::Base.record_timestamps = false
server.updated_at = Time.now.ago(APP_CONFIG.icecast_max_missing_check + 1)
server.save!
ensure
# very important to turn it back; it'll break all tests otherwise
ActiveRecord::Base.record_timestamps = true
end
# should enqueue 1 job # should enqueue 1 job
IcecastConfigWriter.queue_jobs_needing_retry IcecastConfigWriter.queue_jobs_needing_retry

View File

@ -122,6 +122,18 @@ def run_tests? type
ENV["RUN_#{type}_TESTS"] == "1" || ENV[type] == "1" || ENV['ALL_TESTS'] == "1" ENV["RUN_#{type}_TESTS"] == "1" || ENV[type] == "1" || ENV['ALL_TESTS'] == "1"
end end
# you have go out of your way to update 'updated_at '
def set_updated_at(resource, time)
begin
ActiveRecord::Base.record_timestamps = false
resource.updated_at = time
resource.save!(validate: false)
ensure
# very important to turn it back; it'll break all tests otherwise
ActiveRecord::Base.record_timestamps = true
end
end
def wipe_s3_test_bucket def wipe_s3_test_bucket
# don't bother if the user isn't doing AWS tests # don't bother if the user isn't doing AWS tests
if run_tests? :aws if run_tests? :aws

2
update
View File

@ -17,7 +17,7 @@ pushd pb
popd popd
echo "" echo ""
echo "updating database" echo "updating ruby"
echo "" echo ""
pushd ruby pushd ruby
bundle update bundle update

View File

@ -5,7 +5,7 @@ unless ENV["LOCAL_DEV"] == "1"
end end
# Look for $WORKSPACE, otherwise use "workspace" as dev path. # Look for $WORKSPACE, otherwise use "workspace" as dev path.
devenv = ENV["BUILD_NUMBER"].nil? # Jenkins sets a build number environment variable devenv = ENV["BUILD_NUMBER"].nil? || ENV["TEST_WWW"] == "1"
if devenv if devenv
gem 'jam_db', :path=> "../db/target/ruby_package" gem 'jam_db', :path=> "../db/target/ruby_package"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -15,6 +15,12 @@
'exception', 'table' 'exception', 'table'
]; ];
var log_methods = {
'log':null, 'debug':null, 'info':null, 'warn':null, 'error':null, 'assert':null, 'trace':null, 'exception':null
}
var logCache = [];
if ('undefined' === typeof(context.console)) { if ('undefined' === typeof(context.console)) {
context.console = {}; context.console = {};
$.each(console_methods, function(index, value) { $.each(console_methods, function(index, value) {
@ -27,23 +33,39 @@
context.console.debug = function() { console.log(arguments); } context.console.debug = function() { console.log(arguments); }
} }
context.JK.logger = context.console; // http://tobyho.com/2012/07/27/taking-over-console-log/
function takeOverConsole(){
var console = window.console
if (!console) return
function intercept(method){
var original = console[method]
console[method] = function(){
// JW - some code to tone down logging. Uncomment the following, and logCache.push([method].concat(arguments));
// then do your logging to logger.dbg - and it will be the only thing output. if(logCache.length > 50) {
// TODO - find a way to wrap this up so that debug logs can stay in, but this // keep the cache size 50 or lower
// class can provide a way to enable/disable certain namespaces of logs. logCache.pop();
/* }
var fakeLogger = {};
$.each(console_methods, function(index, value) {
fakeLogger[value] = $.noop;
});
fakeLogger.dbg = function(m) {
context.console.debug(m);
};
context.JK.logger = fakeLogger;
*/
if (original.apply){
// Do this for normal browsers
original.apply(console, arguments)
}else{
// Do this for IE
var message = Array.prototype.slice.apply(arguments).join(' ')
original(message)
}
}
}
var methods = ['log', 'warn', 'error']
for (var i = 0; i < methods.length; i++)
intercept(methods[i])
}
takeOverConsole();
context.JK.logger = context.console;
context.JK.logger.logCache = logCache;
})(window, jQuery); })(window, jQuery);

View File

@ -14,15 +14,22 @@
context.JK.JamServer = function (app) { context.JK.JamServer = function (app) {
// uniquely identify the websocket connection
var channelId = null;
var clientType = null;
// heartbeat // heartbeat
var heartbeatInterval = null; var heartbeatInterval = null;
var heartbeatMS = null; var heartbeatMS = null;
var heartbeatMissedMS = 10000; // if 5 seconds go by and we haven't seen a heartbeat ack, get upset var connection_expire_time = null;
var lastHeartbeatSentTime = null;
var lastHeartbeatAckTime = null; var lastHeartbeatAckTime = null;
var lastHeartbeatFound = false; var lastHeartbeatFound = false;
var lastDisconnectedReason = null;
var heartbeatAckCheckInterval = null; var heartbeatAckCheckInterval = null;
var notificationLastSeenAt = undefined; var notificationLastSeenAt = undefined;
var notificationLastSeen = undefined; var notificationLastSeen = undefined;
var clientClosedConnection = false;
// reconnection logic // reconnection logic
var connectDeferred = null; var connectDeferred = null;
@ -53,17 +60,23 @@
server.connected = false; server.connected = false;
function heartbeatStateReset() {
lastHeartbeatSentTime = null;
lastHeartbeatAckTime = null;
lastHeartbeatFound = false;
}
// if activeElementVotes is null, then we are assuming this is the initial connect sequence // if activeElementVotes is null, then we are assuming this is the initial connect sequence
function initiateReconnect(activeElementVotes, in_error) { function initiateReconnect(activeElementVotes, in_error) {
var initialConnect = !!activeElementVotes; var initialConnect = !!activeElementVotes;
freezeInteraction = activeElementVotes && ((activeElementVotes.dialog && activeElementVotes.dialog.freezeInteraction === true) || (activeElementVotes.screen && activeElementVotes.screen.freezeInteraction === true)); freezeInteraction = activeElementVotes && ((activeElementVotes.dialog && activeElementVotes.dialog.freezeInteraction === true) || (activeElementVotes.screen && activeElementVotes.screen.freezeInteraction === true));
if(!initialConnect) { if (!initialConnect) {
context.JK.CurrentSessionModel.onWebsocketDisconnected(in_error); context.JK.CurrentSessionModel.onWebsocketDisconnected(in_error);
} }
if(in_error) { if (in_error) {
reconnectAttempt = 0; reconnectAttempt = 0;
$currentDisplay = renderDisconnected(); $currentDisplay = renderDisconnected();
beginReconnectPeriod(); beginReconnectPeriod();
@ -87,7 +100,7 @@
if (server.connected) { if (server.connected) {
server.connected = false; server.connected = false;
if(app.clientUpdating) { if (app.clientUpdating) {
// we don't want to do a 'cover the whole screen' dialog // we don't want to do a 'cover the whole screen' dialog
// because the client update is already showing. // because the client update is already showing.
return; return;
@ -126,8 +139,9 @@
// check if the server is still sending heartbeat acks back down // check if the server is still sending heartbeat acks back down
// this logic equates to 'if we have not received a heartbeat within heartbeatMissedMS, then get upset // this logic equates to 'if we have not received a heartbeat within heartbeatMissedMS, then get upset
if (new Date().getTime() - lastHeartbeatAckTime.getTime() > heartbeatMissedMS) { if (new Date().getTime() - lastHeartbeatAckTime.getTime() > connection_expire_time) {
logger.error("no heartbeat ack received from server after ", heartbeatMissedMS, " seconds . giving up on socket connection"); logger.error("no heartbeat ack received from server after ", connection_expire_time, " seconds . giving up on socket connection");
lastDisconnectedReason = 'NO_HEARTBEAT_ACK';
context.JK.JamServer.close(true); context.JK.JamServer.close(true);
} }
else { else {
@ -140,6 +154,16 @@
var message = context.JK.MessageFactory.heartbeat(notificationLastSeen, notificationLastSeenAt); var message = context.JK.MessageFactory.heartbeat(notificationLastSeen, notificationLastSeenAt);
notificationLastSeenAt = undefined; notificationLastSeenAt = undefined;
notificationLastSeen = undefined; notificationLastSeen = undefined;
// for debugging purposes, see if the last time we've sent a heartbeat is way off (500ms) of the target interval
var now = new Date();
if (lastHeartbeatSentTime) {
var drift = new Date().getTime() - lastHeartbeatSentTime.getTime() - heartbeatMS;
if (drift > 500) {
logger.error("significant drift between heartbeats: " + drift + 'ms beyond target interval')
}
}
lastHeartbeatSentTime = now;
context.JK.JamServer.send(message); context.JK.JamServer.send(message);
lastHeartbeatFound = false; lastHeartbeatFound = false;
} }
@ -147,11 +171,13 @@
function loggedIn(header, payload) { function loggedIn(header, payload) {
if(!connectTimeout) { if (!connectTimeout) {
clearTimeout(connectTimeout); clearTimeout(connectTimeout);
connectTimeout = null; connectTimeout = null;
} }
heartbeatStateReset();
app.clientId = payload.client_id; app.clientId = payload.client_id;
// tell the backend that we have logged in // tell the backend that we have logged in
@ -159,12 +185,13 @@
$.cookie('client_id', payload.client_id); $.cookie('client_id', payload.client_id);
heartbeatMS = payload.heartbeat_interval * 1000; heartbeatMS = payload.heartbeat_interval * 1000;
logger.debug("jamkazam.js.loggedIn(): clientId now " + app.clientId + "; Setting up heartbeat every " + heartbeatMS + " MS"); connection_expire_time = payload.connection_expire_time * 1000;
logger.debug("jamkazam.js.loggedIn(): clientId=" + app.clientId + ", heartbeat=" + payload.heartbeat_interval + "s, expire_time=" + payload.connection_expire_time + 's');
heartbeatInterval = context.setInterval(_heartbeat, heartbeatMS); heartbeatInterval = context.setInterval(_heartbeat, heartbeatMS);
heartbeatAckCheckInterval = context.setInterval(_heartbeatAckCheck, 1000); heartbeatAckCheckInterval = context.setInterval(_heartbeatAckCheck, 1000);
lastHeartbeatAckTime = new Date(new Date().getTime() + heartbeatMS); // add a little forgiveness to server for initial heartbeat lastHeartbeatAckTime = new Date(new Date().getTime() + heartbeatMS); // add a little forgiveness to server for initial heartbeat
connectDeferred.resolve(); connectDeferred.resolve();
app.activeElementEvent('afterConnect', payload); app.activeElementEvent('afterConnect', payload);
@ -209,10 +236,10 @@
function internetUp() { function internetUp() {
var start = new Date().getTime(); var start = new Date().getTime();
server.connect() server.connect()
.done(function() { .done(function () {
guardAgainstRapidTransition(start, performReconnect); guardAgainstRapidTransition(start, performReconnect);
}) })
.fail(function() { .fail(function () {
guardAgainstRapidTransition(start, closedOnReconnectAttempt); guardAgainstRapidTransition(start, closedOnReconnectAttempt);
}); });
} }
@ -224,18 +251,37 @@
function performReconnect() { function performReconnect() {
if($currentDisplay.is('.no-websocket-connection')) { if(!clientClosedConnection) {
$currentDisplay.hide(); lastDisconnectedReason = 'WEBSOCKET_CLOSED_REMOTELY'
clientClosedConnection = false;
}
else if(!lastDisconnectedReason) {
// let's have at least some sort of type, however generci
lastDisconnectedReason = 'WEBSOCKET_CLOSED_LOCALLY'
}
rest.createDiagnostic({
type: lastDisconnectedReason,
data: {logs: logger.logCache, client_type: clientType, client_id: server.clientID, channel_id: channelId}
})
.always(function() {
if ($currentDisplay.is('.no-websocket-connection')) {
// this path is the 'not in session path'; so there is nothing else to do
$currentDisplay.hide();
// TODO: tell certain elements that we've reconnected
}
else {
// this path is the 'in session' path, where we actually reload the page
context.JK.CurrentSessionModel.leaveCurrentSession()
.always(function () {
window.location.reload();
});
}
server.reconnecting = false;
});
// TODO: tell certain elements that we've reconnected
}
else {
context.JK.CurrentSessionModel.leaveCurrentSession()
.always(function() {
window.location.reload();
});
}
server.reconnecting = false;
} }
function buildOptions() { function buildOptions() {
@ -245,14 +291,14 @@
function renderDisconnected() { function renderDisconnected() {
var content = null; var content = null;
if(freezeInteraction) { if (freezeInteraction) {
var template = $templateDisconnected.html(); var template = $templateDisconnected.html();
var templateHtml = $(context.JK.fillTemplate(template, buildOptions())); var templateHtml = $(context.JK.fillTemplate(template, buildOptions()));
templateHtml.find('.reconnect-countdown').html(formatDelaySecs(reconnectDelaySecs())); templateHtml.find('.reconnect-countdown').html(formatDelaySecs(reconnectDelaySecs()));
content = context.JK.Banner.show({ content = context.JK.Banner.show({
html : templateHtml, html: templateHtml,
type: 'reconnect' type: 'reconnect'
}) ; });
} }
else { else {
var $inSituContent = $(context._.template($templateServerConnection.html(), buildOptions(), { variable: 'data' })); var $inSituContent = $(context._.template($templateServerConnection.html(), buildOptions(), { variable: 'data' }));
@ -267,7 +313,7 @@
} }
function formatDelaySecs(secs) { function formatDelaySecs(secs) {
return $('<span class="countdown-seconds"><span class="countdown">' + secs + '</span> ' + (secs == 1 ? ' second.<span style="visibility:hidden">s</span>' : 'seconds.') + '</span>'); return $('<span class="countdown-seconds"><span class="countdown">' + secs + '</span> ' + (secs == 1 ? ' second.<span style="visibility:hidden">s</span>' : 'seconds.') + '</span>');
} }
function setCountdown($parent) { function setCountdown($parent) {
@ -281,7 +327,7 @@
function renderReconnecting() { function renderReconnecting() {
$currentDisplay.find('.reconnect-progress-msg').text('Attempting to reconnect...') $currentDisplay.find('.reconnect-progress-msg').text('Attempting to reconnect...')
if($currentDisplay.is('.no-websocket-connection')) { if ($currentDisplay.is('.no-websocket-connection')) {
$currentDisplay.find('.disconnected-reconnect').removeClass('reconnect-enabled').addClass('reconnect-disabled'); $currentDisplay.find('.disconnected-reconnect').removeClass('reconnect-enabled').addClass('reconnect-disabled');
} }
else { else {
@ -299,7 +345,7 @@
var now = new Date().getTime(); var now = new Date().getTime();
if ((now - start) < 1500) { if ((now - start) < 1500) {
setTimeout(function() { setTimeout(function () {
nextStep(); nextStep();
}, 1500 - (now - start)) }, 1500 - (now - start))
} }
@ -315,12 +361,12 @@
renderReconnecting(); renderReconnecting();
rest.serverHealthCheck() rest.serverHealthCheck()
.done(function() { .done(function () {
guardAgainstRapidTransition(start, internetUp); guardAgainstRapidTransition(start, internetUp);
}) })
.fail(function(xhr, textStatus, errorThrown) { .fail(function (xhr, textStatus, errorThrown) {
if(xhr && xhr.status >= 100) { if (xhr && xhr.status >= 100) {
// we could connect to the server, and it's alive // we could connect to the server, and it's alive
guardAgainstRapidTransition(start, internetUp); guardAgainstRapidTransition(start, internetUp);
} }
@ -333,7 +379,7 @@
} }
function clearReconnectTimers() { function clearReconnectTimers() {
if(countdownInterval) { if (countdownInterval) {
clearInterval(countdownInterval); clearInterval(countdownInterval);
countdownInterval = null; countdownInterval = null;
} }
@ -341,8 +387,8 @@
function beginReconnectPeriod() { function beginReconnectPeriod() {
// allow user to force reconnect // allow user to force reconnect
$currentDisplay.find('a.disconnected-reconnect').unbind('click').click(function() { $currentDisplay.find('a.disconnected-reconnect').unbind('click').click(function () {
if($(this).is('.button-orange') || $(this).is('.reconnect-enabled')) { if ($(this).is('.button-orange') || $(this).is('.reconnect-enabled')) {
clearReconnectTimers(); clearReconnectTimers();
attemptReconnect(); attemptReconnect();
} }
@ -353,9 +399,9 @@
reconnectDueTime = reconnectingWaitPeriodStart + reconnectDelaySecs() * 1000; reconnectDueTime = reconnectingWaitPeriodStart + reconnectDelaySecs() * 1000;
// update count down timer periodically // update count down timer periodically
countdownInterval = setInterval(function() { countdownInterval = setInterval(function () {
var now = new Date().getTime(); var now = new Date().getTime();
if(now > reconnectDueTime) { if (now > reconnectDueTime) {
clearReconnectTimers(); clearReconnectTimers();
attemptReconnect(); attemptReconnect();
} }
@ -404,9 +450,14 @@
}; };
server.connect = function () { server.connect = function () {
if(!clientType) {
clientType = context.JK.clientType();
}
connectDeferred = new $.Deferred(); connectDeferred = new $.Deferred();
logger.log("server.connect"); channelId = context.JK.generateUUID(); // create a new channel ID for every websocket connection
var uri = context.JK.websocket_gateway_uri; // Set in index.html.erb. logger.log("connecting websocket, channel_id: " + channelId);
var uri = context.JK.websocket_gateway_uri + '?channel_id=' + channelId; // Set in index.html.erb.
//var uri = context.gon.websocket_gateway_uri; // Leaving here for now, as we're looking for a better solution. //var uri = context.gon.websocket_gateway_uri; // Leaving here for now, as we're looking for a better solution.
server.socket = new context.WebSocket(uri); server.socket = new context.WebSocket(uri);
@ -414,9 +465,10 @@
server.socket.onmessage = server.onMessage; server.socket.onmessage = server.onMessage;
server.socket.onclose = server.onClose; server.socket.onclose = server.onClose;
connectTimeout = setTimeout(function() { connectTimeout = setTimeout(function () {
connectTimeout = null; connectTimeout = null;
if(connectDeferred.state() === 'pending') { if (connectDeferred.state() === 'pending') {
server.close(true);
connectDeferred.reject(); connectDeferred.reject();
} }
}, 4000); }, 4000);
@ -427,6 +479,7 @@
server.close = function (in_error) { server.close = function (in_error) {
logger.log("closing websocket"); logger.log("closing websocket");
clientClosedConnection = true;
server.socket.close(); server.socket.close();
closedCleanup(in_error); closedCleanup(in_error);
@ -435,7 +488,7 @@
server.rememberLogin = function () { server.rememberLogin = function () {
var token, loginMessage; var token, loginMessage;
token = $.cookie("remember_token"); token = $.cookie("remember_token");
var clientType = context.jamClient.IsNativeClient() ? 'client' : 'browser';
loginMessage = msg_factory.login_with_token(token, null, clientType); loginMessage = msg_factory.login_with_token(token, null, clientType);
server.send(loginMessage); server.send(loginMessage);
}; };
@ -471,10 +524,11 @@
} }
}; };
// onClose is called if either client or server closes connection
server.onClose = function () { server.onClose = function () {
logger.log("Socket to server closed."); logger.log("Socket to server closed.");
if(connectDeferred.state() === "pending") { if (connectDeferred.state() === "pending") {
connectDeferred.reject(); connectDeferred.reject();
} }
@ -521,19 +575,19 @@
//console.timeEnd('sendP2PMessage'); //console.timeEnd('sendP2PMessage');
}; };
server.updateNotificationSeen = function(notificationId, notificationCreatedAt) { server.updateNotificationSeen = function (notificationId, notificationCreatedAt) {
var time = new Date(notificationCreatedAt); var time = new Date(notificationCreatedAt);
if(!notificationCreatedAt) { if (!notificationCreatedAt) {
throw 'invalid value passed to updateNotificationSeen' throw 'invalid value passed to updateNotificationSeen'
} }
if(!notificationLastSeenAt) { if (!notificationLastSeenAt) {
notificationLastSeenAt = notificationCreatedAt; notificationLastSeenAt = notificationCreatedAt;
notificationLastSeen = notificationId; notificationLastSeen = notificationId;
logger.debug("updated notificationLastSeenAt with: " + notificationCreatedAt); logger.debug("updated notificationLastSeenAt with: " + notificationCreatedAt);
} }
else if(time.getTime() > new Date(notificationLastSeenAt).getTime()) { else if (time.getTime() > new Date(notificationLastSeenAt).getTime()) {
notificationLastSeenAt = notificationCreatedAt; notificationLastSeenAt = notificationCreatedAt;
notificationLastSeen = notificationId; notificationLastSeen = notificationId;
logger.debug("updated notificationLastSeenAt with: " + notificationCreatedAt); logger.debug("updated notificationLastSeenAt with: " + notificationCreatedAt);
@ -573,6 +627,7 @@
} }
function initialize() { function initialize() {
registerLoginAck(); registerLoginAck();
registerHeartbeatAck(); registerHeartbeatAck();
registerSocketClosed(); registerSocketClosed();
@ -584,12 +639,24 @@
$templateServerConnection = $('#template-server-connection'); $templateServerConnection = $('#template-server-connection');
$templateDisconnected = $('#template-disconnected'); $templateDisconnected = $('#template-disconnected');
if($inSituBanner.length != 1) { throw "found wrong number of .server-connection: " + $inSituBanner.length; } if ($inSituBanner.length != 1) {
if($inSituBannerHolder.length != 1) { throw "found wrong number of .no-websocket-connection: " + $inSituBannerHolder.length; } throw "found wrong number of .server-connection: " + $inSituBanner.length;
if($messageContents.length != 1) { throw "found wrong number of .message-contents: " + $messageContents.length; } }
if($dialog.length != 1) { throw "found wrong number of #banner: " + $dialog.length; } if ($inSituBannerHolder.length != 1) {
if($templateServerConnection.length != 1) { throw "found wrong number of #template-server-connection: " + $templateServerConnection.length; } throw "found wrong number of .no-websocket-connection: " + $inSituBannerHolder.length;
if($templateDisconnected.length != 1) { throw "found wrong number of #template-disconnected: " + $templateDisconnected.length; } }
if ($messageContents.length != 1) {
throw "found wrong number of .message-contents: " + $messageContents.length;
}
if ($dialog.length != 1) {
throw "found wrong number of #banner: " + $dialog.length;
}
if ($templateServerConnection.length != 1) {
throw "found wrong number of #template-server-connection: " + $templateServerConnection.length;
}
if ($templateDisconnected.length != 1) {
throw "found wrong number of #template-disconnected: " + $templateDisconnected.length;
}
} }
this.initialize = initialize; this.initialize = initialize;

View File

@ -7,18 +7,8 @@
var logger = context.JK.logger; var logger = context.JK.logger;
var myTrackCount; var myTrackCount;
var ASSIGNMENT = { var ASSIGNMENT = context.JK.ASSIGNMENT;
CHAT: -2, var VOICE_CHAT = context.JK.VOICE_CHAT;
OUTPUT: -1,
UNASSIGNED: 0,
TRACK1: 1,
TRACK2: 2
};
var VOICE_CHAT = {
NO_CHAT: "0",
CHAT: "1"
};
var instrument_array = []; var instrument_array = [];

View File

@ -179,51 +179,42 @@
// Defaulting to 1st instrument in profile always at the moment. // Defaulting to 1st instrument in profile always at the moment.
data.tracks = tracks; data.tracks = tracks;
var jsonData = JSON.stringify(data);
$('#btn-create-session').addClass('button-disabled'); $('#btn-create-session').addClass('button-disabled');
$('#btn-create-session').bind('click', false); $('#btn-create-session').bind('click', false);
var url = "/api/sessions"; rest.legacyCreateSession(data)
$.ajax({ .done(function(response) {
type: "POST", var newSessionId = response.id;
dataType: "json", var invitationCount = inviteMusiciansUtil.createInvitations(newSessionId, function() {
contentType: 'application/json', context.location = '/client#/session/' + newSessionId;
url: url, });
processData:false, // Re-loading the session settings will cause the form to reset with the right stuff in it.
data: jsonData, // This is an extra xhr call, but it keeps things to a single codepath
success: function(response) { loadSessionSettings();
var newSessionId = response.id; $('#btn-create-session').removeClass('button-disabled');
var invitationCount = inviteMusiciansUtil.createInvitations(newSessionId, function() { $('#btn-create-session').unbind('click', false);
context.location = '/client#/session/' + newSessionId;
});
// Re-loading the session settings will cause the form to reset with the right stuff in it.
// This is an extra xhr call, but it keeps things to a single codepath
loadSessionSettings();
$('#btn-create-session').removeClass('button-disabled');
$('#btn-create-session').unbind('click', false);
context.JK.GA.trackSessionCount(data.musician_access, data.fan_access, invitationCount); context.JK.GA.trackSessionCount(data.musician_access, data.fan_access, invitationCount);
context.JK.GA.trackSessionMusicians(context.JK.GA.SessionCreationTypes.create);
},
error: function(jqXHR) {
var handled = false;
if(jqXHR.status = 422) {
var response = JSON.parse(jqXHR.responseText);
if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") {
app.notifyAlert("No Inputs Configured", $('<span>You will need to reconfigure your audio device.</span>'));
handled = true;
}
}
if(!handled) {
app.notifyServerError(jqXHR, "Unable to Create Session");
}
$('#btn-create-session').removeClass('button-disabled');
$('#btn-create-session').unbind('click', false);
context.JK.GA.trackSessionMusicians(context.JK.GA.SessionCreationTypes.create);
})
.fail(function(jqXHR) {
var handled = false;
if(jqXHR.status = 422) {
var response = JSON.parse(jqXHR.responseText);
if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") {
app.notifyAlert("No Inputs Configured", $('<span>You will need to reconfigure your audio device.</span>'));
handled = true;
}
} }
}); if(!handled) {
app.notifyServerError(jqXHR, "Unable to Create Session");
}
$('#btn-create-session').removeClass('button-disabled');
$('#btn-create-session').unbind('click', false);
})
return false; return false;
} }

View File

@ -286,7 +286,7 @@
function renderFeeds(feeds) { function renderFeeds(feeds) {
$.each(feeds.entries, function(i, feed) { $.each(feeds.entries, function(i, feed) {
if(feed.type == 'music_session_history') { if(feed.type == 'music_session') {
var options = { var options = {
feed_item: feed, feed_item: feed,
status_class: feed['is_over?'] ? 'ended' : 'inprogress', status_class: feed['is_over?'] ? 'ended' : 'inprogress',

View File

@ -19,6 +19,11 @@
join : "Join" join : "Join"
}; };
var sessionQualityTypes = {
good : "Good",
poor : "Poor"
};
var invitationTypes = { var invitationTypes = {
email : "Email", email : "Email",
facebook : "Facebook", facebook : "Facebook",
@ -83,6 +88,7 @@
audioTest : "AudioTest", audioTest : "AudioTest",
sessionCount : "SessionCount", sessionCount : "SessionCount",
sessionMusicians : "SessionMusicians", sessionMusicians : "SessionMusicians",
sessionQuality : "SessionQuality",
invite : "Invite", invite : "Invite",
findSession : "FindSession", findSession : "FindSession",
friendConnect : "Connect", friendConnect : "Connect",
@ -174,6 +180,11 @@
context.ga('send', 'event', categories.sessionMusicians, joinOrCreate); context.ga('send', 'event', categories.sessionMusicians, joinOrCreate);
} }
function trackSessionQuality(goodOrPoor) {
assertOneOf(goodOrPoor, sessionQualityTypes);
context.ga('send', 'event', categories.sessionQuality, goodOrPoor);
}
function trackServiceInvitations(invitationType, numInvited) { function trackServiceInvitations(invitationType, numInvited) {
assertOneOf(invitationType, invitationTypes); assertOneOf(invitationType, invitationTypes);
assertNumber(numInvited); assertNumber(numInvited);
@ -271,6 +282,7 @@
var GA = {}; var GA = {};
GA.Categories = categories; GA.Categories = categories;
GA.SessionCreationTypes = sessionCreationTypes; GA.SessionCreationTypes = sessionCreationTypes;
GA.SessionQualityTypes = sessionQualityTypes;
GA.InvitationTypes = invitationTypes; GA.InvitationTypes = invitationTypes;
GA.FriendConnectTypes = friendConnectTypes; GA.FriendConnectTypes = friendConnectTypes;
GA.RecordingActions = recordingActions; GA.RecordingActions = recordingActions;
@ -281,6 +293,7 @@
GA.trackFTUECompletion = trackFTUECompletion; GA.trackFTUECompletion = trackFTUECompletion;
GA.trackSessionCount = trackSessionCount; GA.trackSessionCount = trackSessionCount;
GA.trackSessionMusicians = trackSessionMusicians; GA.trackSessionMusicians = trackSessionMusicians;
GA.trackSessionQuality = trackSessionQuality;
GA.trackServiceInvitations = trackServiceInvitations; GA.trackServiceInvitations = trackServiceInvitations;
GA.trackFindSessions = trackFindSessions; GA.trackFindSessions = trackFindSessions;
GA.virtualPageView = virtualPageView; GA.virtualPageView = virtualPageView;

View File

@ -6,6 +6,8 @@
context.JK = context.JK || {}; context.JK = context.JK || {};
context.JK.GearWizard = function (app) { context.JK.GearWizard = function (app) {
var ASSIGNMENT = context.JK.ASSIGNMENT;
var VOICE_CHAT = context.JK.VOICE_CHAT;
var $dialog = null; var $dialog = null;
var $wizardSteps = null; var $wizardSteps = null;
@ -20,11 +22,11 @@
// populated by loadDevices // populated by loadDevices
var deviceInformation = null; var deviceInformation = null;
var musicInputPorts = null; var musicPorts = null;
var musicOutputPorts = null;
// SELECT DEVICE STATE
var validScore = false; var validLatencyScore = false;
var validIOScore = false;
// SELECT TRACKS STATE // SELECT TRACKS STATE
@ -46,7 +48,7 @@
display: 'MacOSX Built-In', display: 'MacOSX Built-In',
videoURL: undefined videoURL: undefined
}, },
MACOSX_interface: { MacOSX_interface: {
display: 'MacOSX external interface', display: 'MacOSX external interface',
videoURL: undefined videoURL: undefined
}, },
@ -86,13 +88,19 @@
var $bufferIn = $currentWizardStep.find('.select-buffer-in'); var $bufferIn = $currentWizardStep.find('.select-buffer-in');
var $bufferOut = $currentWizardStep.find('.select-buffer-out'); var $bufferOut = $currentWizardStep.find('.select-buffer-out');
var $frameSize = $currentWizardStep.find('.select-frame-size'); var $frameSize = $currentWizardStep.find('.select-frame-size');
var $inputPorts = $currentWizardStep.find('.input-ports'); var $inputChannels = $currentWizardStep.find('.input-ports');
var $outputPorts = $currentWizardStep.find('.output-ports'); var $outputChannels = $currentWizardStep.find('.output-ports');
var $scoreReport = $currentWizardStep.find('.results'); var $scoreReport = $currentWizardStep.find('.results');
var $latencyScoreSection = $scoreReport.find('.latency-score-section');
var $latencyScore = $scoreReport.find('.latency-score'); var $latencyScore = $scoreReport.find('.latency-score');
var $ioScoreSection = $scoreReport.find('.io-score-section');
var $ioRateScore = $scoreReport.find('.io-rate-score'); var $ioRateScore = $scoreReport.find('.io-rate-score');
var $ioVarScore = $scoreReport.find('.io-var-score'); var $ioVarScore = $scoreReport.find('.io-var-score');
var $ioCountdown = $scoreReport.find('.io-countdown');
var $ioCountdownSecs = $scoreReport.find('.io-countdown .secs');
var $nextButton = $ftueButtons.find('.btn-next'); var $nextButton = $ftueButtons.find('.btn-next');
var $asioControlPanelBtn = $currentWizardStep.find('.asio-settings-btn');
var $resyncBtn = $currentWizardStep.find('resync-btn')
// should return one of: // should return one of:
// * MacOSX_builtin // * MacOSX_builtin
@ -126,22 +134,31 @@
} }
} }
function loadDevices() { function loadDevices() {
var devices = context.jamClient.FTUEGetDevices(false);
var oldDevices = context.jamClient.FTUEGetDevices(false);
var devices = context.jamClient.FTUEGetAudioDevices();
console.log("oldDevices: " + JSON.stringify(oldDevices));
console.log("devices: " + JSON.stringify(devices));
var loadedDevices = {}; var loadedDevices = {};
// augment these devices by determining their type // augment these devices by determining their type
context._.each(devices, function (displayName, deviceId) { context._.each(devices.devices, function (device) {
if(device.name == "JamKazam Virtual Monitor") {
return;
}
var deviceInfo = {}; var deviceInfo = {};
deviceInfo.id = deviceId; deviceInfo.id = device.guid;
deviceInfo.type = determineDeviceType(deviceId, displayName); deviceInfo.type = determineDeviceType(device.guid, device.display_name);
console.log("deviceInfo.type: " + deviceInfo.type)
deviceInfo.displayType = audioDeviceBehavior[deviceInfo.type].display; deviceInfo.displayType = audioDeviceBehavior[deviceInfo.type].display;
deviceInfo.displayName = displayName; deviceInfo.displayName = device.display_name;
loadedDevices[deviceId] = deviceInfo; loadedDevices[device.guid] = deviceInfo;
logger.debug("loaded device: ", deviceInfo); logger.debug("loaded device: ", deviceInfo);
}) })
@ -179,7 +196,7 @@
function initializeNextButtonState() { function initializeNextButtonState() {
$nextButton.removeClass('button-orange button-grey'); $nextButton.removeClass('button-orange button-grey');
if (validScore) $nextButton.addClass('button-orange'); if (validLatencyScore) $nextButton.addClass('button-orange');
else $nextButton.addClass('button-grey'); else $nextButton.addClass('button-grey');
} }
@ -218,71 +235,66 @@
context.JK.dropdown($bufferOut); context.JK.dropdown($bufferOut);
} }
// finds out if the $port argument is from a different port pair than what's currently selected
function isNewlySelectedPair($port) {
var portId = $port.attr('data-id');
// get all inputs currently selected except this one
var $selectedInputs = $inputPorts.find('input[type="checkbox"]:checked').filter('[data-id="' + portId + '"]');
console.log("$selectedInputs", $selectedInputs); // reloads the backend's channel state for the currently selected audio devices,
var isNewlySelected = true; // and update's the UI accordingly
context._.each($selectedInputs, function($current) { function initializeChannels() {
var testPairInfo = $($current).data('pair'); musicPorts = jamClient.FTUEGetChannels();
console.log("musicPorts: %o", JSON.stringify(musicPorts));
context._.each(testPairInfo.ports, function(port) { initializeInputPorts(musicPorts);
// if we can find the newly selected item in this pair, then it's not a different pair... initializeOutputPorts(musicPorts);
if(port.id == portId) { }
isNewlySelected = false;
return false; // break loop
}
});
if(isNewlySelected) return false; // break loop // during this phase of the FTUE, we have to assign selected input channels
// to tracks. The user, however, does not have a way to indicate which channel
// goes to which track (that's not until the next step of the wizard).
// so, we just auto-generate a valid assignment
function newInputAssignment() {
var assigned = 0;
context._.each(musicPorts.inputs, function(inputChannel) {
if(isChannelAssigned(inputChannel)) {
assigned += 1;
}
}); });
return isNewlySelected; var newAssignment = Math.floor(assigned / 2) + 1;
return newAssignment;
} }
// set checkbox state for all items in the pair function inputChannelChanged() {
function setCheckedForAllInPair($portBox, pairInfo, checked, signalBackend) {
context._.each(pairInfo.ports, function(port) {
var portId = port.id;
var $input = $portBox.find('input[type="checkbox"][data-id="' + portId + '"]');
if($input.is(':checked') != checked) {
if(checked) {
$input.iCheck('check').attr('checked', 'checked');
//context.jamClient.FTUESetMusicInput2($input.id);
}
else {
$input.iCheck('uncheck').removeAttr('checked');
//context.jamClient.FTUEUnsetMusicInput2($input.id);
}
}
})
}
function inputPortChanged() {
if(iCheckIgnore) return; if(iCheckIgnore) return;
var $checkbox = $(this); var $checkbox = $(this);
var portId = $checkbox.data('data-id'); var channelId = $checkbox.attr('data-id');
var inputPortChecked = $checkbox.is(':checked'); var isChecked = $checkbox.is(':checked');
console.log('inputPortChecked: ' + inputPortChecked);
if(inputPortChecked) { if(isChecked) {
if(isNewlySelectedPair($checkbox)) { var newAssignment = newInputAssignment();
setCheckedForAllInPair($inputPorts, $checkbox.data('pair'), true, true); logger.debug("assigning input channel %o to track: %o", channelId, newAssignment);
} context.jamClient.TrackSetAssignment(channelId, true, newAssignment);
else {
//context.jamClient.FTUESetMusicInput2($input.id);
}
} }
else { else {
// context.jamClient.FTUEUnsetMusicInput2($input.id);; logger.debug("unassigning input channel %o", channelId);
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.UNASSIGNED);
// unassigning creates a hole in our auto-assigned tracks. reassign them all to keep it consistent
var $assignedInputs = $inputChannels.find('input[type="checkbox"]:checked');
var assigned = 0;
context._.each($assignedInputs, function(assignedInput) {
var $assignedInput = $(assignedInput);
var assignedChannelId = $assignedInput.attr('data-id');
var newAssignment = Math.floor(assigned / 2) + 1;
logger.debug("re-assigning input channel %o to track: %o", assignedChannelId, newAssignment);
context.jamClient.TrackSetAssignment(assignedChannelId, true, newAssignment);
assigned += 1;
});
} }
initializeChannels();
} }
// should be called in a ifChanged callback if you want to cancel. bleh. // should be called in a ifChanged callback if you want to cancel.
// you have to use this instead of 'return false' like a typical input 'change' event.
function cancelICheckChange($checkbox) { function cancelICheckChange($checkbox) {
iCheckIgnore = true; iCheckIgnore = true;
var checked = $checkbox.is(':checked'); var checked = $checkbox.is(':checked');
@ -293,58 +305,64 @@
}, 1); }, 1);
} }
function outputPortChanged() { function outputChannelChanged() {
if(iCheckIgnore) return; if(iCheckIgnore) return;
var $checkbox = $(this); var $checkbox = $(this);
var portId = $checkbox.data('data-id'); var channelId = $checkbox.attr('data-id');
var outputPortChecked = $checkbox.is(':checked'); var isChecked = $checkbox.is(':checked');
console.log('outputPortChecked: ' + outputPortChecked);
if(outputPortChecked) { // don't allow more than 2 output channels selected at once
var $selectedInputs = $outputPorts.find('input[type="checkbox"]:checked').filter('[data-id="' + portId + '"]'); if($outputChannels.find('input[type="checkbox"]:checked').length > 2) {
$selectedInputs.iCheck('uncheck').removeAttr('checked'); context.JK.Banner.showAlert('You can only have a maximum of 2 output ports selected.');
var pairInfo = $checkbox.data('pair');
setCheckedForAllInPair($outputPorts, pairInfo, true, false);
console.log("Setting music output");
context.jamClient.FTUESetMusicOutput(pairInfo.ports.map(function(i) {return i.id}).join(PROFILE_DEV_SEP_TOKEN));
}
else {
context.JK.Banner.showAlert('You must have at least one output pair selected.');
// can't allow uncheck of last output // can't allow uncheck of last output
cancelICheckChange($checkbox); cancelICheckChange($checkbox);
return;
} }
if(isChecked) {
logger.debug("assigning output channel %o", channelId);
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.OUTPUT);
}
else {
logger.debug("unassigning output channel %o", channelId);
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.UNASSIGNED);
}
initializeChannels();
} }
function initializeInputPorts(inputPorts) { // checks if it's an assigned OUTPUT or ASSIGNED CHAT
context._.each(inputPorts, function(inputPairs) { function isChannelAssigned(channel) {
// there is no guarantee that a pair has two items. return channel.assignment == ASSIGNMENT.CHAT || channel.assignment == ASSIGNMENT.OUTPUT || channel.assignment > 0;
context._.each(inputPairs.ports, function(inputInPair) { }
var inputPort = $(context._.template($templateAudioPort.html(), inputInPair, { variable: 'data' }));
var $checkbox = inputPort.find('input'); function initializeInputPorts(musicPorts) {
$checkbox.data('pair', inputPairs); // so when it's selected, we can see what other ports, if any, are in the same pair $inputChannels.empty();
context.JK.checkbox($checkbox); var inputPorts = musicPorts.inputs;
$checkbox.on('ifChanged', inputPortChanged); context._.each(inputPorts, function(inputChannel) {
$inputPorts.append(inputPort); var $inputChannel = $(context._.template($templateAudioPort.html(), inputChannel, { variable: 'data' }));
}); var $checkbox = $inputChannel.find('input');
if(isChannelAssigned(inputChannel)) {
$checkbox.attr('checked', 'checked');
}
context.JK.checkbox($checkbox);
$checkbox.on('ifChanged', inputChannelChanged);
$inputChannels.append($inputChannel);
}); });
} }
function initializeOutputPorts(outputPorts) { function initializeOutputPorts(musicPorts) {
var first = true; $outputChannels.empty();
context._.each(outputPorts, function(outputPairs) { var outputChannels = musicPorts.outputs;
context._.each(outputPairs.ports, function(outputInPair) { context._.each(outputChannels, function(outputChannel) {
var outputPort = $(context._.template($templateAudioPort.html(), outputInPair, { variable: 'data' })); var $outputPort = $(context._.template($templateAudioPort.html(), outputChannel, { variable: 'data' }));
var $checkbox = outputPort.find('input'); var $checkbox = $outputPort.find('input');
$checkbox.data('pair', outputPairs); // so when it's selected, we can see what other ports, if any, are in the same pair if(isChannelAssigned(outputChannel)) {
context.JK.checkbox($checkbox); $checkbox.attr('checked', 'checked');
$checkbox.on('ifChanged', outputPortChanged);
$outputPorts.append(outputPort);
});
if(first) {
first = false;
setCheckedForAllInPair($outputPorts, outputPairs, true, false);
} }
context.JK.checkbox($checkbox);
$checkbox.on('ifChanged', outputChannelChanged);
$outputChannels.append($outputPort);
}); });
} }
@ -364,11 +382,11 @@
} }
function clearInputPorts() { function clearInputPorts() {
$inputPorts.empty(); $inputChannels.empty();
} }
function clearOutputPorts() { function clearOutputPorts() {
$outputPorts.empty(); $outputChannels.empty();
} }
function resetScoreReport() { function resetScoreReport() {
@ -377,6 +395,27 @@
$latencyScore.empty(); $latencyScore.empty();
} }
function renderLatencyScore(latencyValue, latencyClass) {
if(latencyValue) {
$latencyScore.text(latencyValue + ' ms');
}
else {
$latencyScore.text('');
}
$latencyScoreSection.removeClass('good acceptable bad unknown starting').addClass(latencyClass);
}
// std deviation is the worst value between in/out
// media is the worst value between in/out
// io is the value returned by the backend, which has more info
// ioClass is the pre-computed rollup class describing the result in simple terms of 'good', 'acceptable', bad'
function renderIOScore(std, median, ioData, ioClass) {
$ioRateScore.text(median ? median : '');
$ioVarScore.text(std ? std : '');
$ioScoreSection.removeClass('good acceptable bad unknown starting skip').addClass(ioClass);
// TODO: show help bubble of all data in IO data
}
function updateScoreReport(latencyResult) { function updateScoreReport(latencyResult) {
var latencyClass = "neutral"; var latencyClass = "neutral";
var latencyValue = 'N/A'; var latencyValue = 'N/A';
@ -387,37 +426,69 @@
if (latencyValue <= 10) { if (latencyValue <= 10) {
latencyClass = "good"; latencyClass = "good";
validLatency = true; validLatency = true;
} else if (latency.latency <= 20) { } else if (latencyValue <= 20) {
latencyClass = "acceptable"; latencyClass = "acceptable";
validLatency = true; validLatency = true;
} else { } else {
latencyClass = "bad"; latencyClass = "bad";
} }
} }
else {
latencyClass = 'unknown';
}
validScore = validLatency; // validScore may become based on IO variance too validLatencyScore = validLatency;
$latencyScore.html(latencyValue + ' ms'); renderLatencyScore(latencyValue, latencyClass);
} }
function audioInputDeviceUnselected() { function audioInputDeviceUnselected() {
validScore = false; validLatencyScore = false;
initializeNextButtonState(); initializeNextButtonState();
resetFrameBuffers(); resetFrameBuffers();
clearInputPorts(); clearInputPorts();
} }
function renderScoringStarted() { function renderScoringStarted() {
validScore = false; validLatencyScore = false;
initializeNextButtonState(); initializeNextButtonState();
resetScoreReport(); resetScoreReport();
freezeAudioInteraction();
renderLatencyScore(null, 'starting');
} }
function renderScoringStopped() { function renderScoringStopped() {
initializeNextButtonState(); initializeNextButtonState();
unfreezeAudioInteraction();
} }
function freezeAudioInteraction() {
$audioInput.attr("disabled", "disabled").easyDropDown('disable');
$audioOutput.attr("disabled", "disabled").easyDropDown('disable');
$frameSize.attr("disabled", "disabled").easyDropDown('disable');
$bufferIn.attr("disabled", "disabled").easyDropDown('disable');
$bufferOut.attr("disabled", "disabled").easyDropDown('disable');
$asioControlPanelBtn.on("click", false);
$resyncBtn.on('click', false);
iCheckIgnore = true;
$inputChannels.find('input[type="checkbox"]').iCheck('disable');
$outputChannels.find('input[type="checkbox"]').iCheck('disable');
}
function unfreezeAudioInteraction() {
$audioInput.removeAttr("disabled").easyDropDown('enable');
$audioOutput.removeAttr("disabled").easyDropDown('enable');
$frameSize.removeAttr("disabled").easyDropDown('enable');
$bufferIn.removeAttr("disabled").easyDropDown('enable');
$bufferOut.removeAttr("disabled").easyDropDown('enable');
$asioControlPanelBtn.off("click", false);
$resyncBtn.off('click', false);
$inputChannels.find('input[type="checkbox"]').iCheck('enable');
$outputChannels.find('input[type="checkbox"]').iCheck('enable');
iCheckIgnore = false;
}
// Given a latency structure, update the view. // Given a latency structure, update the view.
function newFtueUpdateLatencyView(latency) { function newFtueUpdateLatencyView(latency) {
var $report = $('.ftue-new .latency .report'); var $report = $('.ftue-new .latency .report');
@ -506,44 +577,52 @@
}); });
} }
function initializeAudioInputChanged() { function renderIOScoringStarted(secondsLeft) {
$audioInput.unbind('change').change(function (evt) { $ioCountdownSecs.text(secondsLeft);
$ioCountdown.show();
}
var audioDeviceId = selectedAudioInput(); function renderIOScoringStopped() {
if (!audioDeviceId) { $ioCountdown.hide();
}
function renderIOCountdown(secondsLeft) {
$ioCountdownSecs.text(secondsLeft);
}
function attemptScore() {
var audioInputDeviceId = selectedAudioInput();
var audioOutputDeviceId = selectedAudioOutput();
if (!audioInputDeviceId) {
audioInputDeviceUnselected(); audioInputDeviceUnselected();
return false; return false;
} }
var audioDevice = findDevice(selectedAudioInput()); var audioInputDevice = findDevice(audioInputDeviceId);
if (!audioDevice) { if (!audioInputDevice) {
context.JK.alertSupportedNeeded('Unable to find device information for: ' + audioDeviceId); context.JK.alertSupportedNeeded('Unable to find information for input device: ' + audioInputDeviceId);
return false; return false;
} }
if(!audioOutputDeviceId) {
audioOutputDeviceId = audioInputDeviceId;
}
var audioOutputDevice = findDevice(audioOutputDeviceId);
if (!audioInputDevice) {
context.JK.alertSupportedNeeded('Unable to find information for output device: ' + audioOutputDeviceId);
return false;
}
jamClient.FTUESetInputMusicDevice(audioInputDeviceId);
jamClient.FTUESetOutputMusicDevice(audioOutputDeviceId);
renderScoringStarted(); initializeChannels();
jamClient.FTUESetMusicDevice(audioDeviceId); jamClient.FTUESetInputLatency(selectedBufferIn());
jamClient.FTUESetOutputLatency(selectedBufferOut());
// enumerate input and output ports
musicInputPorts = jamClient.FTUEGetMusicInputs2();
console.log(JSON.stringify(musicInputPorts));
// [{"inputs":[{"id":"i~5~Built-in Microph~0~0","name":"Built-in Microph - Left"},{"id":"i~5~Built-in Microph~1~0","name":"Built-in Microph - Right"}]}]
musicOutputPorts = jamClient.FTUEGetMusicOutputs2();
console.log(JSON.stringify(musicOutputPorts));
// [{"outputs":[{"id":"o~5~Built-in Output~0~0","name":"Built-in Output - Left"},{"id":"o~5~Built-in Output~1~0","name":"Built-in Output - Right"}]}]
initializeInputPorts(musicInputPorts);
initializeOutputPorts(musicOutputPorts);
jamClient.FTUESetInputLatency(selectedAudioInput());
jamClient.FTUESetOutputLatency(selectedAudioOutput());
jamClient.FTUESetFrameSize(selectedFramesize()); jamClient.FTUESetFrameSize(selectedFramesize());
renderScoringStarted();
logger.debug("Calling FTUESave(false)"); logger.debug("Calling FTUESave(false)");
jamClient.FTUESave(false); jamClient.FTUESave(false);
@ -551,8 +630,67 @@
console.log("FTUEGetExpectedLatency: %o", latency); console.log("FTUEGetExpectedLatency: %o", latency);
updateScoreReport(latency); updateScoreReport(latency);
renderScoringStopped();
}); // if there was a valid latency score, go on to the next step
if(validLatencyScore) {
renderIOScore(null, null, null, 'starting');
var testTimeSeconds = 10; // allow 10 seconds for IO to establish itself
context.jamClient.FTUEStartIoPerfTest();
renderIOScoringStarted(testTimeSeconds);
renderIOCountdown(testTimeSeconds);
var interval = setInterval(function() {
testTimeSeconds -= 1;
renderIOCountdown(testTimeSeconds);
if(testTimeSeconds == 0) {
clearInterval(interval);
renderIOScoringStopped();
var io = context.jamClient.FTUEGetIoPerfData();
console.log("io: ", io);
// take the higher variance, which is apparently actually std dev
var std = io.in_var > io.out_var ? io.in_var : io.out_var;
std = Math.round(std * 100) / 100;
// take the furthest-off-from-target io rate
var median = Math.abs(io.in_median - io.in_target ) > Math.abs(io.out_median - io.out_target ) ? [io.in_median, io.in_target] : [io.out_median, io.out_target];
var medianTarget = median[1];
median = Math.round(median[0]);
var stdIOClass = 'bad';
if(std <= 0.50) {
stdIOClass = 'good';
}
else if(std <= 1.00) {
stdIOClass = 'acceptable';
}
var medianIOClass = 'bad';
if(Math.abs(median - medianTarget) <= 1) {
medianIOClass = 'good';
}
else if(Math.abs(median - medianTarget) <= 2) {
medianIOClass = 'acceptable';
}
// now base the overall IO score based on both values.
renderIOScore(std, median, io, ioClass);
// lie for now until IO questions finalize
validIOScore = true;
renderScoringStopped();
}
}, 1000);
}
else {
renderIOScore(null, null, null, 'skip');
renderScoringStopped();
}
}
function initializeAudioInputChanged() {
$audioInput.unbind('change').change(attemptScore);
} }
function initializeAudioOutputChanged() { function initializeAudioOutputChanged() {
@ -677,7 +815,31 @@
$currentWizardStep = null; $currentWizardStep = null;
} }
// checks if we already have a profile called 'FTUE...'; if not, create one. if so, re-use it.
function findOrCreateFTUEProfile() {
var profileName = context.jamClient.FTUEGetMusicProfileName();
logger.debug("current profile name: " + profileName);
if(profileName && profileName.indexOf('FTUE') == 0) {
}
else {
var newProfileName = 'FTUEAttempt-' + new Date().getTime().toString();
logger.debug("setting FTUE-prefixed profile name to: " + newProfileName);
context.jamClient.FTUESetMusicProfileName(newProfileName);
}
var profileName = context.jamClient.FTUEGetMusicProfileName();
logger.debug("name on exit: " + profileName);
}
function beforeShow(args) { function beforeShow(args) {
context.jamClient.FTUECancel();
findOrCreateFTUEProfile();
step = args.d1; step = args.d1;
if (!step) step = 0; if (!step) step = 0;
step = parseInt(step); step = parseInt(step);
@ -689,7 +851,7 @@
} }
function afterHide() { function afterHide() {
context.jamClient.FTUECancel();
} }
function back() { function back() {

View File

@ -14,7 +14,20 @@
UNIX: "Unix" UNIX: "Unix"
}; };
// TODO: store these client_id values in instruments table, or store context.JK.ASSIGNMENT = {
CHAT: -2,
OUTPUT: -1,
UNASSIGNED: 0,
TRACK1: 1,
TRACK2: 2
};
context.JK.VOICE_CHAT = {
NO_CHAT: "0",
CHAT: "1"
};
// TODO: store these client_id values in instruments table, or store
// server_id as the client_id to prevent maintenance nightmares. As it's // server_id as the client_id to prevent maintenance nightmares. As it's
// set up now, we will have to deploy each time we add new instruments. // set up now, we will have to deploy each time we add new instruments.
context.JK.server_to_client_instrument_map = { context.JK.server_to_client_instrument_map = {

View File

@ -32,8 +32,8 @@
$.each(response.musicians, function(index, val) { $.each(response.musicians, function(index, val) {
var instrumentHtml = ''; var instrumentHtml = '';
musicianHtml += '<tr><td width="50"><a href="#" class="avatar-tiny"><img src="' + context.JK.resolveAvatarUrl(val.photo_url) + '" /></a></td>'; musicianHtml += '<tr><td width="50"><a user-id="' + val.id + '" profileaction="musician" class="avatar-tiny"><img src="' + context.JK.resolveAvatarUrl(val.photo_url) + '" /></a></td>';
musicianHtml += '<td width="75"><a href="#">' + val.name + '</a></td>'; musicianHtml += '<td width="75"><<a user-id="' + val.id + '" profileaction="musician">' + val.name + '</a></td>';
instrumentHtml = '<td><div class="nowrap">'; instrumentHtml = '<td><div class="nowrap">';
if (val.instruments) { // @FIXME: edge case for Test user that has no instruments? if (val.instruments) { // @FIXME: edge case for Test user that has no instruments?
@ -75,6 +75,8 @@
}); });
$(hoverSelector).append('<h2>Band Detail</h2>' + bandHtml); $(hoverSelector).append('<h2>Band Detail</h2>' + bandHtml);
context.JK.bindProfileClickEvents(hoverSelector);
configureActionButtons(response); configureActionButtons(response);
}) })
.fail(function(xhr) { .fail(function(xhr) {

View File

@ -36,19 +36,21 @@
followingHtml += '<tr>'; followingHtml += '<tr>';
} }
var avatarUrl, profilePath; var avatarUrl, attrId, type;
if (val.type === "band") { if (val.type === "band") {
avatarUrl = context.JK.resolveBandAvatarUrl(val.photo_url); avatarUrl = context.JK.resolveBandAvatarUrl(val.photo_url);
profilePath = "bandProfile"; attrId = "band-id";
type = "band";
} }
else { else {
avatarUrl = context.JK.resolveAvatarUrl(val.photo_url); avatarUrl = context.JK.resolveAvatarUrl(val.photo_url);
profilePath = "profile"; attrId = "user-id";
type = "musician";
} }
followingHtml += '<td width="24"><a href="#" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>'; followingHtml += '<td width="24"><a ' + attrId + '="' + val.id + '" profileaction="' + type + '" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>';
followingHtml += '<td><a href="/client#/' + profilePath + '/' + val.id + '"><strong>' + val.name + '</strong></a></td>'; followingHtml += '<td><a ' + attrId + '="' + val.id + '" profileaction="' + type + '"><strong>' + val.name + '</strong></a></td>';
if (index % 2 > 0) { if (index % 2 > 0) {
followingHtml += '</tr>'; followingHtml += '</tr>';
@ -76,6 +78,8 @@
}); });
$(hoverSelector).append('<h2>Fan Detail</h2>' + fanHtml); $(hoverSelector).append('<h2>Fan Detail</h2>' + fanHtml);
context.JK.bindProfileClickEvents(hoverSelector);
configureActionButtons(response); configureActionButtons(response);
}) })
.fail(function(xhr) { .fail(function(xhr) {

View File

@ -42,19 +42,21 @@
followingHtml += '<tr>'; followingHtml += '<tr>';
} }
var avatarUrl, profilePath; var avatarUrl, attrId, type;
if (val.type === "band") { if (val.type === "band") {
avatarUrl = context.JK.resolveBandAvatarUrl(val.photo_url); avatarUrl = context.JK.resolveBandAvatarUrl(val.photo_url);
profilePath = "bandProfile"; attrId = "band-id";
type = "band";
} }
else { else {
avatarUrl = context.JK.resolveAvatarUrl(val.photo_url); avatarUrl = context.JK.resolveAvatarUrl(val.photo_url);
profilePath = "profile"; attrId = "user-id";
type = "musician";
} }
followingHtml += '<td width="24"><a href="#" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>'; followingHtml += '<td width="24"><a ' + attrId + '="' + val.id + '" profileaction="' + type + '" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>';
followingHtml += '<td><a href="/client#/' + profilePath + '/' + val.id + '"><strong>' + val.name + '</strong></a></td>'; followingHtml += '<td><a ' + attrId + '="' + val.id + '" profileaction="' + type + '"><strong>' + val.name + '</strong></a></td>';
if (index % 2 > 0) { if (index % 2 > 0) {
followingHtml += '</tr>'; followingHtml += '</tr>';
@ -101,6 +103,8 @@
}); });
$(hoverSelector).append('<h2>Musician Detail</h2>' + musicianHtml); $(hoverSelector).append('<h2>Musician Detail</h2>' + musicianHtml);
context.JK.bindProfileClickEvents(hoverSelector);
configureActionButtons(response); configureActionButtons(response);
}) })
.fail(function(xhr) { .fail(function(xhr) {

View File

@ -34,6 +34,30 @@
}); });
} }
function legacyCreateSession(options) {
return $.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: "/api/sessions/legacy",
processData:false,
data: JSON.stringify(options)});
}
function legacyJoinSession(options) {
var sessionId = options["session_id"];
delete options["session_id"];
return $.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: "/api/sessions/" + sessionId + "/participants/legacy",
data: JSON.stringify(options),
processData:false
});
}
function findSessions(query) { function findSessions(query) {
return $.ajax({ return $.ajax({
type: "GET", type: "GET",
@ -109,7 +133,7 @@
function addPlayablePlay(playableId, playableType, claimedRecordingId, userId) { function addPlayablePlay(playableId, playableType, claimedRecordingId, userId) {
if (playableType == 'JamRuby::Recording') { if (playableType == 'JamRuby::Recording') {
context.JK.GA.trackRecordingPlay(); context.JK.GA.trackRecordingPlay();
} else if (playableType == 'JamRuby::MusicSessionHistory') { } else if (playableType == 'JamRuby::MusicSession') {
context.JK.GA.trackSessionPlay(); context.JK.GA.trackSessionPlay();
} }
return $.ajax({ return $.ajax({
@ -961,6 +985,16 @@
url: '/api/sessions/' + musciSessionId + '/chats?' + $.param(options), url: '/api/sessions/' + musciSessionId + '/chats?' + $.param(options),
dataType: "json", dataType: "json",
contentType: 'application/json' contentType: 'application/json'
})
};
function createDiagnostic(options) {
return $.ajax({
type: "POST",
url: '/api/diagnostics',
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(options)
}); });
} }
@ -970,6 +1004,8 @@
// Expose publics // Expose publics
this.initialize = initialize; this.initialize = initialize;
this.legacyCreateSession = legacyCreateSession;
this.legacyJoinSession = legacyJoinSession;
this.getUserDetail = getUserDetail; this.getUserDetail = getUserDetail;
this.getCities = getCities; this.getCities = getCities;
this.getRegions = getRegions; this.getRegions = getRegions;
@ -1048,6 +1084,7 @@
this.getNotifications = getNotifications; this.getNotifications = getNotifications;
this.createChatMessage = createChatMessage; this.createChatMessage = createChatMessage;
this.getChatMessages = getChatMessages; this.getChatMessages = getChatMessages;
this.createDiagnostic = createDiagnostic;
return this; return this;
}; };

Some files were not shown because too many files have changed in this diff Show More