Merge branch 'develop' of https://bitbucket.org/jamkazam/jam-cloud into develop

This commit is contained in:
root 2014-07-31 17:08:14 +02:00
commit d4e2c88994
31 changed files with 200 additions and 65 deletions

View File

@ -199,4 +199,5 @@ track_user_in_scores.sql
median_aggregate.sql
current_scores_use_median.sql
current_scores_ams_index_sms_index_use_user_instrument.sql
locidispid_in_score_histories.sql
locidispid_in_score_histories.sql
define_environment_in_db.sql

View File

@ -0,0 +1,3 @@
-- https://jamkazam.atlassian.net/browse/VRFS-1951
-- we need to know the environment in the database for advanced behaviors
ALTER TABLE generic_state ADD COLUMN env VARCHAR(255) NOT NULL DEFAULT 'development';

View File

@ -450,7 +450,7 @@ module JamRuby
[music_sessions, user_scores]
end
def self.participant_create user, music_session_id, client_id, as_musician, tracks
def self.participant_create user, music_session_id, client_id, as_musician, tracks, audio_latency
music_session = MusicSession.find(music_session_id)
if music_session.active_music_session
@ -462,7 +462,7 @@ module JamRuby
active_music_session.with_lock do # VRFS-1297
active_music_session.tick_track_changes
connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, 10)
connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency)
if connection.errors.any?
# rollback the transaction to make sure nothing is disturbed in the database
@ -519,7 +519,7 @@ module JamRuby
# auto-join this user into the newly created session
as_musician = true
connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, 10)
connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency)
unless connection.errors.any?
user.update_progression_field(:first_music_session_at)

View File

@ -140,8 +140,7 @@ INNER JOIN users ON users.id = msess.user_id
INNER JOIN rsvp_slots AS rs ON rs.music_session_id = msess.id
LEFT JOIN rsvp_requests_rsvp_slots AS rrrs ON rrrs.rsvp_slot_id = rs.id
WHERE
musician_access = 't' AND
approval_required = 'f' AND
open_rsvps = TRUE AND
users.last_jam_locidispid IS NOT NULL AND
msess.created_at > '#{earliest_session_create_time}' AND
msess.created_at < '#{latest_session_create_time}' AND

View File

@ -4,6 +4,21 @@ module JamRuby
self.table_name = 'generic_state'
validates :env, :inclusion => {:in => ['development', 'staging', 'production', 'test']}
def self.allow_emails?
database_environment = singleton.env
# if the database says we are in production/staging, then the config has to also agree and say we are in production/staging to send emails
# this is to protect against developers loading a staging or production environment and possibly sending emails to
# we even go one step further, and make sure ENV['BUILD_NUMBER'] is set, which is something you do in production, but would be very rare in development
# or if your database says 'development' and config say 'development', then we allow emails to go out too
(!ENV['BUILD_NUMBER'].nil? && (Environment.mode == 'production' || Environment.mode == 'staging') && (database_environment == 'production' || database_environment == 'staging')) ||
(database_environment == 'development' && Environment.mode == 'development')
end
def self.singleton
GenericState.find('default')
end

View File

@ -10,7 +10,7 @@ module JamRuby
RECURRING_MODES = [NO_RECURRING, RECURRING_WEEKLY]
attr_accessor :legal_terms, :language_description, :access_description
attr_accessor :legal_terms, :language_description, :access_description, :scheduling_info_changed
attr_accessor :approved_rsvps, :open_slots, :pending_invitations
@ -58,11 +58,17 @@ module JamRuby
before_create :generate_share_token
before_create :add_to_feed
#before_save :update_scheduled_start
before_save :check_scheduling_info_changed
SHARE_TOKEN_LENGTH = 8
SEPARATOR = '|'
def check_scheduling_info_changed
@scheduling_info_changed = scheduled_start_changed?
true
end
def add_to_feed
feed = Feed.new
feed.music_session = self

View File

@ -89,6 +89,16 @@ describe EmailBatchScheduledSessions do
expect(UserMailer.deliveries.length).to eq(2)
end
it "won't find an open_rsvps=false session" do
session1.open_rsvps = false
session1.save!
session2.open_rsvps = false
session2.save!
obj = scheduled_batch.fetch_recipients
expect(obj.count).to eq(0)
end
it 'handles large batches' do
creators = []
8.downto(1) do |nn|

View File

@ -0,0 +1,61 @@
require 'spec_helper'
describe GenericState do
def database_env (env)
singleton = GenericState.singleton
singleton.env = env
singleton.save!
end
def rails_env (env)
JamRuby::Environment.should_receive(:mode).any_number_of_times.and_return(env)
end
describe "allow_emails?" do
it "allows emails if database is production and env is production, with build number" do
database_env('production')
rails_env('production')
stub_const("ENV", {'BUILD_NUMBER' => 1})
GenericState.allow_emails?.should be_true
end
it "no emails if database is production and env is production, no build number" do
database_env('production')
rails_env('production')
stub_const("ENV", {'BUILD_NUMBER' => nil})
GenericState.allow_emails?.should be_false
end
it "allows emails if database is development and env is development" do
database_env('development')
rails_env('development')
GenericState.allow_emails?.should be_true
end
it "no emails if database development, and environment is test" do
database_env('development')
rails_env('test')
GenericState.allow_emails?.should be_false
end
it "no emails if database production, and environment is development" do
database_env('production')
rails_env('development')
stub_const("ENV", {'BUILD_NUMBER' => 1})
GenericState.allow_emails?.should be_false
end
it "no emails if database production, and environment is test" do
database_env('production')
rails_env('development')
GenericState.allow_emails?.should be_false
end
end
end

View File

@ -779,5 +779,20 @@ describe MusicSession do
end
end
end
describe "scheduled session rescheduled logic" do
it "detect change to scheduling info" do
music_session1.description = "Hey!"
music_session1.save!
music_session1.scheduling_info_changed.should be_false
music_session1.scheduled_start = Time.now - 1.days
music_session1.save!
music_session1.scheduling_info_changed.should be_true
end
end
end

View File

@ -203,6 +203,19 @@
return temp;
},
convertPercentToAudioTaper: function (input) {
// composite function resembling audio taper
if (input <= 1) { return -80; }
if (input <= 28) { return (2 * input - 80); }
if (input <= 79) { return (0.5 * input - 38); }
if (input < 99) { return (0.875 * input - 67.5); }
if (input >= 99) { return 20; }
},
setFaderValue: function (faderId, faderValue) {
var $fader = $('[fader-id="' + faderId + '"]');
this.setHandlePosition($fader, faderValue);

View File

@ -273,11 +273,11 @@
}
function clearResults() {
$('table#sessions-active').empty();
$('table#sessions-active').find("tr:gt(0)").remove();
currentScheduledSessionsPage = 0;
$ssScroller.infinitescroll('resume');
$('table#sessions-scheduled').empty();
$('table#sessions-scheduled').find("tr:gt(0)").remove();
$ssNoMoreEntries.hide();
}

View File

@ -883,11 +883,7 @@
dataType: "json",
contentType: 'application/json',
url: "/api/users/progression/certified_gear",
processData: false,
data: JSON.stringify({
success: options.success,
reason: options.reason
})
data: JSON.stringify(options)
});
}
@ -1184,17 +1180,6 @@
});
}
function updateAudioLatency(options) {
var id = getId(options);
return $.ajax({
type: "POST",
url: '/api/users/' + id + '/audio_latency',
dataType: "json",
contentType: 'application/json',
data: options,
});
}
function initialize() {
return self;
}
@ -1298,7 +1283,6 @@
this.getChatMessages = getChatMessages;
this.createDiagnostic = createDiagnostic;
this.getLatencyTester = getLatencyTester;
this.updateAudioLatency = updateAudioLatency;
return this;
};

View File

@ -570,21 +570,25 @@
}
function startSessionClicked() {
var $btn = $(this);
if($btn.is('.disabled')) { return; }
$btn.addClass('disabled')
if(willOptionStartSession()) {
gearUtils.guardAgainstInvalidConfiguration(app)
.fail(function() {
$btn.removeClass('disabled')
app.notify(
{ title: "Unable to Start New Session",
text: "You can only start a session once you have working audio gear and a tested internet connection."
})
})
.done(function(){
startSession();
startSession($btn);
});
}
else {
startSession();
startSession($btn);
}
}
@ -593,7 +597,7 @@
return createType == "immediately" || createType == "schedule-future" || createType == "rsvp";
}
function startSession() {
function startSession($startBtn) {
var data = {};
@ -700,6 +704,7 @@
context.JK.GA.trackSessionMusicians(context.JK.GA.SessionCreationTypes.create);
})
.fail(function(jqXHR) {
$startBtn.removeClass('disabled');
var handled = false;
if(jqXHR.status = 422) {
var response = JSON.parse(jqXHR.responseText);
@ -712,6 +717,8 @@
app.notifyServerError(jqXHR, "Unable to Create Session");
}
})
.always(function() {
})
};
@ -735,9 +742,10 @@
}
})
.fail(function(jqXHR){
$startBtn.removeClass('disabled');
logger.debug("unable to schedule a session")
app.notifyServerError(jqXHR, "Unable to schedule a session");
});
})
}
}

View File

@ -569,6 +569,7 @@
$voiceChat.show();
$voiceChat.attr('mixer-id', mixer.id);
var $voiceChatGain = $voiceChat.find('.voicechat-gain');
$voiceChatGain.attr('mixer-id', mixer.id);
var $voiceChatMute = $voiceChat.find('.voicechat-mute').attr('mixer-id', mixer.id);
var gainPercent = percentFromMixerValue(
mixer.range_low, mixer.range_high, mixer.volume_left);
@ -1147,8 +1148,8 @@
// volumes on trackVolumeObject, and call SetControlState to stick.
var sliderValue = percentToMixerValue(
currentMixerRangeMin, currentMixerRangeMax, volumePercent);
context.trackVolumeObject.volL = sliderValue;
context.trackVolumeObject.volR = sliderValue;
context.trackVolumeObject.volL = context.JK.FaderHelpers.convertPercentToAudioTaper(volumePercent);
context.trackVolumeObject.volR = context.JK.FaderHelpers.convertPercentToAudioTaper(volumePercent);
// Special case for L2M mix:
if (mixerId === '__L2M__') {
logger.debug("L2M volumePercent=" + volumePercent);

View File

@ -433,7 +433,7 @@
context.JK.GA.trackAudioTestData(uniqueDeviceName(), context.JK.GA.AudioTestDataReasons.pass, latencyScore);
rest.userCertifiedGear({success: true, client_id: app.clientId, audio_latency: getLatencyScore()});
rest.userCertifiedGear({success: true, client_id: app.clientId, audio_latency: getLatencyScore().latency});
}
function onGearTestFail(e, data) {

View File

@ -269,14 +269,6 @@
return result;
}
gearUtils.updateAudioLatency = function(app) {
var latency = jamClient.FTUEGetExpectedLatency().latency;
return rest.updateAudioLatency({client_id: app.clientId, audio_latency: latency})
.fail(function(jqXHR) {
app.notifyServerError(jqXHR, "Unable to sync audio latency")
});
}
// if the user has a good user network score, immediately returns with a resolved deferred object.
// if not, the user will have the network test dialog prompted... once it's closed, then you'll be told reject() if score is still bad, or resolve() if now good
gearUtils.guardAgainstBadNetworkScore = function(app) {

View File

@ -224,7 +224,8 @@ class ApiMusicSessionsController < ApiController
response.status = :unprocessable_entity
respond_with @music_session
else
Notification.send_scheduled_session_rescheduled(@music_session)
Notification.send_scheduled_session_rescheduled(@music_session) if @music_session.scheduling_info_changed
respond_with @music_session, responder: ApiResponder, :location => api_session_history_detail_url(@music_session)
end
else
@ -287,7 +288,8 @@ class ApiMusicSessionsController < ApiController
params[:id],
params[:client_id],
params[:as_musician],
params[:tracks]
params[:tracks],
params[:audio_latency]
)
if @connection.errors.any?

View File

@ -24,6 +24,9 @@ class ApiScoringController < ApiController
conn = Connection.where(client_id: clientid, user_id: current_user.id).first
if conn.nil? then render :json => {message: 'session not found'}, :status => 404; return end
if conn.locidispid.nil? then render :json => {message: 'no locidispid for connection'}, :status => 404; return end
# if !current_user.id.eql?(conn.user.id) then render :json => {message: 'session not owned by user'}, :status => 403; return end
result_client_ids = JamRuby::GetWork.get_work_list(conn.locidispid, conn.addr)

View File

@ -534,7 +534,7 @@ class ApiUsersController < ApiController
if !@user.errors.any?
# update audio gear latency information
@user.update_audio_latency(connection, params[:audio_latency])
@user.update_audio_latency(connection, params[:audio_latency]) if params[:audio_latency]
end
else
@user.failed_qualification(params[:reason])

View File

@ -197,11 +197,11 @@ class UsersController < ApplicationController
@slides = [
Slide.new("JamKazam Overview", "web/carousel_musicians.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/VexH4834o9I?autoplay=1"),
Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/DBo--aj_P1w?autoplay=1"),
Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/zJ68hA8-fLA?autoplay=1"),
Slide.new("JamKazam Overview", "web/carousel_musicians.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/VexH4834o9I?autoplay=1"),
Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1")
Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/DBo--aj_P1w?autoplay=1"),
Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/zJ68hA8-fLA?autoplay=1")
]
@promo_buzz = PromoBuzz.active

View File

@ -89,7 +89,7 @@
%td
{{data.latency}}
.right
%a{href: "/client#/profile/{{data.user_id}}", class: 'button-orange left', 'user-id' => "{{data.user_id}}", target: "_blank"} PROFILE
%a{href: "/client#/profile/{{data.user_id}}", class: 'button-orange left', 'user-id' => "{{data.user_id}}"} PROFILE
%a{href: "#", class: 'button-orange left approveRsvpRequest', 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}"} APPROVE
%a{href: "#", class: 'button-orange left declineRsvpRequest', 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}"} DECLINE
.clearall

View File

@ -1,7 +1,7 @@
<h2><%= title %></h2>
<br/>
<div class="findsession-container">
<table class="findsession-table" cellspacing="0" cellpadding="0" border="0">
<table id="<%= category %>" class="findsession-table" cellspacing="0" cellpadding="0" border="0">
<!-- header -->
<tr>
<th align="left" width="30%">SESSION</th>
@ -12,7 +12,4 @@
</tr>
<!-- session row goes here -->
</table>
<table id="<%= category %>" class="findsession-table" cellspacing="0" cellpadding="0" border="0">
<!-- session row goes here -->
</table>
</div>

View File

@ -170,11 +170,11 @@
%h2 Tutorial Videos
%ul
%li
%a{href: '#'} Creating a Session
%a{href: 'https://www.youtube.com/watch?v=EZZuGcDUoWk', rel: 'external'} Creating a Session
%li
%a{href: '#'} Finding a Session
%a{href: 'https://www.youtube.com/watch?v=xWponSJo-GU', rel: 'external'} Finding a Session
%li
%a{href: '#'} Playing in a Session
%a{href: 'https://www.youtube.com/watch?v=zJ68hA8-fLA', rel: 'external'} Playing in a Session
%li
%a{href: '#'} Connecting with Other Musicians
%li
@ -184,9 +184,9 @@
%h2 Other Valuable Resource Links
%ul
%li
%a{href: '#'} JamKazam Support Center
%a{href: 'https://jamkazam.desk.com/', rel: 'external'} JamKazam Support Center
%li
%a{href: '#'} JamKazam Community Forum
%a{href: 'http://forums.jamkazam.com', rel: 'external'} JamKazam Community Forum
.wizard-buttons
%script{type: 'text/template', id: 'template-ftuesteps'}

View File

@ -1,5 +1,7 @@
@@log = Logging.logger['EmailInitializer']
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.delivery_method = Rails.env == "test" ? :test : :smtp
ActionMailer::Base.delivery_method = GenericState.allow_emails? ? :smtp : :test
ActionMailer::Base.smtp_settings = {
:address => Rails.application.config.email_smtp_address,
:port => Rails.application.config.email_smtp_port,
@ -8,4 +10,6 @@ ActionMailer::Base.smtp_settings = {
:user_name => Rails.application.config.email_smtp_user_name,
:password => Rails.application.config.email_smtp_password ,
:enable_starttls_auto => Rails.application.config.email_smtp_starttls_auto
}
}
@@log.debug("ActionMailer.delivery_method = #{ActionMailer::Base.delivery_method}")

View File

@ -1,7 +1,7 @@
Resque.redis = Rails.application.config.redis_host
if !$rails_rake_task && Rails.env == 'development' && ENV['RUN_JOBS_INLINE'] == '1'
if !$rails_rake_task && Rails.env == 'development' && (ENV['RUN_JOBS_INLINE'] == '1' || ENV['RUN_INLINE_JOBS'] == '1')
Thread.new do
system('INTERVAL=1 bundle exec rake all_jobs')

View File

@ -16,7 +16,20 @@ task :scheduler => :environment do
# The schedule doesn't need to be stored in a YAML, it just needs to
# be a hash. YAML is usually the easiest.
Resque.schedule = YAML.load_file(File.join(File.dirname(__FILE__), '../..', 'config/scheduler.yml'))
config = YAML.load_file(File.join(File.dirname(__FILE__), '../..', 'config/scheduler.yml'))
if File.exist? File.join(File.dirname(__FILE__), '../..', 'config/scheduler_override.yml')
puts "scheduler_override file found. loading..."
override = YAML.load_file(File.join(File.dirname(__FILE__), '../..', 'config/scheduler_override.yml'))
if override # override will be false if file is empty
config.merge!(override)
else
puts "schedule_override is empty... skipping..."
end
end
Resque.schedule = config
# If your schedule already has +queue+ set for each job, you don't
# need to require your jobs. This can be an advantage since it's

View File

@ -8,6 +8,7 @@ describe "Profile History", :js => true, :type => :feature, :capybara_feature =>
before do
MusicSession.delete_all
ActiveMusicSession.delete_all
Recording.delete_all
set_login_cookie user
stub_const("APP_CONFIG", web_config)

View File

@ -108,7 +108,6 @@ describe "Musician Search API", :type => :api do
expect(@user4.followers.count).to be 3
get_query(orderby: :followed)
good_response
puts last_response.body
musician = json["musicians"][0]
expect(musician["id"]).to eq(@user4.id)
followings = musician['followings']

View File

@ -6,13 +6,18 @@ def bputs(msg)
end
end
bputs "before simplecov"
require 'simplecov'
bputs "before rubygems"
require 'rubygems'
bputs "before omniauth"
#require 'spork'
require 'omniauth'
#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'
ENV["RAILS_ENV"] ||= 'test'
bputs "before activerecord load"
@ -28,7 +33,6 @@ bputs "before db_config load"
db_config = YAML::load(File.open('config/database.yml'))["test"]
# initialize ActiveRecord's db connection\
bputs "before recreate db"
SpecDb::recreate_database(db_config)

View File

@ -54,6 +54,10 @@ def web_config
def max_track_part_upload_failures
3
end
def icecast_hardcoded_source_password
'blueberryjam'
end
end
klass.new
end

View File

@ -543,7 +543,7 @@ def change_session_genre #randomly just change it
find('#session-settings-dialog') # ensure the dialog is visible
within('#session-settings-dialog') do
wait_for_ajax
@new_genre = get_options(here).-(["Select Genre"]).-(selected_genres).sample.to_s
@new_genre = get_options(here).-(["Select Genre", "Unspecified"]).-(selected_genres).sample.to_s
jk_select(@new_genre, '#session-settings-dialog select[name="genres"]')
wait_for_ajax
find('#session-settings-dialog-submit').trigger(:click)